Currently building a REST API and one of the functions of it will be to create users. There are two ways my application will create users:
Register, users add themselves with the usual data: email, password, username, date of birth.
Manual creation, admin adds a user with usual data AND any extra data as required.
My setup is a users table, users_metadata table and users_permissions table, as well as a few others. The email and password are stored in the users table, the username and date of birth in the users_metadata table. When manually creating a user other metadata and the user's permissions, as well as data in the other tables, can be changed.
Would it be better to have two different resources to handle creating a user?
Would it be better to have two different resources to handle creating a user?
I wouldn't create two different resources that both represent the user and both model its creation process. Since a user is a user, in my opinion they should be created trough the same resource.
Manual creation, admin adds a user with usual data AND any extra data as required.
When manually creating a user other metadata and the user's permissions, as well as data in the other tables, can be changed.
If it makes sense, you could model this extra data as a separate (sub)resource. The same goes for permissions. This sub resource can then have its own URL (for instance /users/{id}/meta and /users/{id}/permissions) to which the client issues separate POST requests, or it can be nested in the data structure that is sent to the API, like so:
{
"name": "John",
"email-address": "john#doe.com",
"permissions": {
"read": true,
"write": false
},
"meta-data": {
"date-of-birth": "2000-01-01"
}
}
The approach with separate sub resources at their own URLs makes access control and validation a bit easier. On the other hand, it puts a bigger burden on the client. It can also put you in the position where an admin creates a user, the basic information is saved, but there is an error saving permissions; depending on your use case you may or may not need to somehow handle that automatically.
The approach where the sub resources are nested in the data structure makes the logic to handle the POST request a bit more complex, but it does make the client side of things easier and gives you the option to make the whole action atomic by wrapping it in a transaction and rolling back if anything goes wrong.
Note: These two approaches are not mutually exclusive; you can do both if you want.
Which of these approaches is best will depend on how many sub resources there are, how complex they are and how complex the access control to the sub resources is; the more sub resources there are and/or the more complex access control is, the more likely I would be to setup different URLs for the sub resources.
In this specific case, I would net the sub resources in the data structure and have the clients POST all the data at once.
Related
I am currently working on my first headless system.
The API is written in PHP.
It basically consists of three parts:
endpoints
functions
output
Each request to an endpoint is passed to a function which passes the database response to the output.
In order to keep the number of functions manageable, I have made them relatively general.
For example, the lists of customers and employees are created by the same function and the corresponding table is passed via a parameter in the URL.
Now I want to create a rights management system in which the users have different roles and access is thus restricted.
I have thought of three possibilities for this:
Everything only in the frontend
Not a good idea, as it is easily hackable.
Integrate the entire restriction into the output function.
That's safe, but all records are queried first and then the ones that are not allowed are sorted.
Make the database queries "even" more dynamic.
So each query to the database only asks for the rows that the respective role is allowed to see or change.
This is very time-consuming and the idea of creating general functions is actually obsolete, because they then become very complex.
Is the last, the usual way?
Are there other concepts?
I am currently working with a medium-sized team developing a custom content management system for a large client. The CMS is written using PHP and follows the MVC pattern (custom). It is a modular system, for which plugins can be added to the system by us or other developers at a later stage.
The system will contain user-based permissions, and a series of generic roles that have predefined permissions. It is required that a super-admin user can also modify permissions on a user basis (for example John Doe might be defined as a regular user, but has the possibility of modifying content).
Opinion is currently divided about the best way for us to store and handle these permissions. Half of the dev team are suggesting to add a new DB table that will store key/value pairs and user IDs for each user, with boolean values stored in each record. The table structure would be something like this:
user_ID: the ID of the user
perm_name: the name of the permission
perm_value: a boolean value dictating whether the user can carry out this action
The proposal is that if the value associated with a particular permission is set to 0, or does not exist in the table, the user does not have the required permission.
The other half of the dev team is favouring storing the permissions in a single field as a JSON-encoded string within the users table. So for example, we would store the following JSON for John Doe):
{
'modifyProducts': 1,
'addProducts': 1,
'addPages': 0
}
We would then be able to use json_decode() within the User class to extract the permissions, for example:
$this->permissions = json_decode($dbval);
I am personally leaning towards the latter option for two main reasons:
It is scalable
It does not require us to modify the database if we need a new permissions.
In short, what is the best approach for such an application?
I think the best solution in this case would be to use NoSQL database, such as MongoDB - this way you can still keep the scalability and take advantage of the JSON structure.
On the other hand, depending on your user table you could take possible advantage of column type indexing and optimize your requests for querying and reading, if of course you're working with normalized database.
I personally would store JSON within a relational DB only when I want to directly display the info and not use it for any querying. Just like you've said yourself - there's always the possibility of ending up with huge and growing JSON string and this would most probably cause troubles at some point.
I've been working on a web app for a few months now. It's a PHP and MySQL driven database app which relates objects between each other.
I'd like to add functionality so that someone could register to use it and set up a monthly subscription. When they log in the app would simply populate with data from their own database.
I've done some scouring online but I'm struggling to find a starting point for adding this sort of feature.
The app relies on half a dozen tables within a database. So I'm also not sure if creating an individual database per user is practical.
Creating a db per user is very rarely the way to go - it's complicated and has very few benefits with lots of drawbacks (eg maintaining multiple simultaneous Db connections as most libraries only connect to a single Db). What you really need to do is create a user table and then tag various records with a UserId.
When a user registers, create a new User record, then create their new entries in other tables all referencing that Id. (Actually, only the "root" of each relational object needs a UserId eg If you have Order and OrderItems only the Order table needs a UserId)
Without more detail, it's impossible to help further.
Incidentally, the only time you should consider db-per-user is if each user requires unique tables (in which case your app would have to be very complex to actually use the data) or if there are security concerns re: storing data together (more likely with multiple clients than multiple users).
I have built a web application for one user, but now I would like to offer it to many users (it's an application for photographer(s)).
Multiple databases problems
I first did this by creating an application for each user, but this has many problems, like:
Giving access to a new user can't be automated (or is very difficult) since I have to create a subdomain, a database, initial tables, copy code to a new location, etc. This is tedious to do by hand!
I can't as easily create reports and statistics of usage, like how many projects do my users have, how many photos, etc.
Single database problems
But having just one database for each users creates it's own problems in code:
Now I have to change the DB schema to accommodate extra users, like the projects table having a user_id column (the same goes for some other tables like settings, etc.).
I have to look at almost each line of code that accesses the database and edit the SQL for selecting and inserting, so that I sava data for that specific user, at the same time doing joins so that I check permissions (select ... from projects inner join project_users ... where user_id = ?).
If I forget to do that at one spot in the code it means security breach or another unpleasant thing (consider showing user's projects by just doing select * from projects like I used to do - it will show all users' projects).
Backup: backup is harder because there's more data for the whole database and if a user says: "hey, I made a mistake today, can you revert the DB to yesterday", I can't as easily do that.
A solution?
I have read multiple questions on stackoverflow and have decided that I should go the "single database" route. But I'd like to get rid of the problems, if it's possible.
So I was thinking if there was a way to segment my database somehow so that I don't get these nasty (sometimes invisible) bugs?
I can reprogram the DB access layer if needed, but I'm using SQLs and not OO getter and setter methods.
Any help would be greatly appreciated.
I don't think there's a silver bullet on this one - though there are some things you can do.
Firstly, you could have your new design use a different MySQL user, and deny that user "select" rights on tables that should only be accessed through joins with the "users" table. You can then create a view which joins the two tables together, and use that whenever you run "select" queries. This way, if you forget a query, it will fail spectacularly, instead of silently. You can of course also limit insert, update and delete in this way - though that's a lot harder with a view.
Edit
So, if your application currently connects as "web_user", you could revoke select access on the projects table from that user. Instead, you'd create a view "projects_for_users", and grant "select" permissions on that view to a new user - "photographer", perhaps. The new user should also not have select access to "projects".
You could then re-write the application's data access step by step, and you'd be sure that you'd caught every instance where your app selects projects, because it would explode when trying to retrieve data - neither of your users would have "select" permissions on the projects table.
As a little side bonus - the select permission is also required for updates with a where clause, so you'd also be able to find instances where the application updates the project table without having been rewritten.
Secondly, you want to think about the provisioning process - how will you grant access to the system to new users? Who does this? Again, by separating the database user who can insert records into "users", you can avoid stupid bugs where page in your system does more than you think it does. With this kind of system, there are usually several steps that make up the provisioning process. Make sure you separate out the privileges for those tasks from the regular user privileges.
Edit
Provisioning is the word for setting up a service for a new user (I think it comes from the telephony world, where phone companies will talk about provisioning a new service on an existing phone line). It usually includes a whole bunch of business processes - and each step in the process must succeed for the next one to start. So, in your app, you may need to set up a new user account, validate their email address, set up storage space etc. Each of those steps needs to be considered as a step in the process, not just a single task.
Finally, while you're doing this, you may as well think about different levels of privilege. Will your system merit different types of user? Photographers, who can upload work, reviewers who can't? If that's a possible feature extension, you may want to build support for that now, even if the only type of user you support on go-live is photographer.
Well, time to face some hard facts -- I think. The "single database problem" that you describe, is not a problem, but a normal (usual) design. Quite often, one is simply a special case of many.
For some reason you have designed a web-app for one user -- not many of those around.
So, time to re-design.
I have been creating a web app and am looking to expand. In my web app I have a table for users which includes privileges in order to track whether a user is an administrator, a very small table for a dynamic content section of a page, and a table for tracking "events" on the website.
Being not very experienced with web application creation, I'm not really sure about how professionals would create systems of databases and tables for a web application. In my web app, I plan to add further user settings for each member of the website and even a messaging system. I currently use PHP with a MySQL database that I query for all of my commands, but I would be willing to change any of this if necessary. What would be the best wat to track content such as messages that are interpersonal and also specific user settings for each user. Would I want to have multiple databases at any point? Would I want to have multiple tables for each user, perhaps? Any information on how this is done or should be done would be quite helpful.
I'm sorry about the broadness of the question, but I've been wanting to reform this web app since I feel that my ideas for table usage are not on par with those that experienced programmers have.
Here's my seemingly long, hopefully not too convoluted answer to your question. I think I've covered most, if not all of your queries.
For your web app, you could have a table of users called "Users", settings table called "UserSettings" or something equally as descriptive, and messages in "PrivateMessages" table. Then there could be child tables that store extra data that is required.
User security can be a tricky thing to design and implement. Do you want to do it by groups (if you plan on having many users, making it easier to manage their permissions), or just assign individually due to a small user base? For security alone, you'd end up with 4 tables:
Users
UserSettings
UserGroups
UserAssignedGroups
That way you can have user info, settings, groups they can be assigned to and what they ARE assigned to separated properly. This gives you a decent amount of flexibility and conforms to normalization standards (as mentioned above by DrSAR).
With your messages, don't store them with the username, but rather the User ID. For instance, in your PrivateMessages table, you would have a MessageID, SenderUserID, RecipientUserID, Subject, Body and DateSent to store the most basic info. That way, when a user wants to check their received messages, you can query the table saying:
SELECT * FROM PrivateMessages WHERE RecipientUserID = 123556
A list of tables for your messages could be as such:
PrivateMessages
MessageReplies
The PrivateMessages table can store the parent message, and then the MessageReplies table can store the subsequent replies. You could store it all in one table, but depending on traffic and possibly writing recursive functions to retrieve all messages and replies from one table, a two table approach would be simplest I feel.
If I were you, I'd sit down with a pencil and paper, and write down/draw what I want to track in my database. That way you can then draw links between what you want to store, and see how it will come together. It helps me when I'm trying to visualise things.
For the scope of your web app you don't need multiple databases. You do need, however, multiple tables to store your data efficiently.
For user settings, always use a separate table. You want your "main" users table as lean as possible, since it will be accessed (= searched) every time a user will try to log in. Store IDs, username, password (hashed, of course) and any other field that you need to access when authenticating. Put all the extra information in a separate table. That way your login will only query a smaller table and once the user is authenticated you can use its ID to get all other information from the secondary table(s).
Messages can be trickier because they're a bigger order of magnitude - you might have tens or hundreds for each user. You need to design you table structure based on your application's logic. A table for each user is clearly not a feasible solution, so go for a general messages table but implement procedures to keep it to a manageable size. An example would be "archiving" messages older than X days, which would move them to another table (which works well if your users aren't likely to access their old messages too often). But like I said, it depends on your application.
Good luck!
Along the lines of Cristian Radu's comments: you need to split your data into different tables. The lean user table will (in fact, should) have one unique ID per user. This (unique) key should be repeated in the secondary tables. It will then be called a foreign key. Obviously, you want a key that's unique. If your username can be guaranteed to be unique (i.e. you require user be identified by their email address), then you can use that. If user names are real names (e.g. Firstname Sirname), then you don't have that guarantee and you need to keep a userid which becomes your key. Similarly, the table containing your posts could (but doesn't have to) have a field with unique userids indicating who wrote it etc.
You might want to read a bit about database design and the concept of normalization: (http://dev.mysql.com/tech-resources/articles/intro-to-normalization.html) No need to get bogged down with the n-th form of normalization but it will help you at this stage where you need to figure out the database design.
Good luck and report back ;-)