I need to implement a URL whitelist to limit the number of pages that a javascript widget can be deployed on.

The requesting domain is already limited for an account, but I now want to restrict each account to a list of up to 7 paths.

Theres a couple of layers I can think of / combine, but none of them alone seem "correct"

  • UI




The UI seems the easiest, the CSRF token means that only this form can post to the management module, if it only has 7 fields, it can only post a maximum of 7 paths. But I know the UI should present the persisted data and perform some basic validation before sending it to the backend, not enforce the business logic of it.

The database, An RDBMS (As far as I know) can only really enforce this if the account table has a 7 whitelist fields, or a single account_whitelist table with a foreign key of account id and 7 whitelist fields. I don't think I can restrict a maximum number of occurrences of the foreign key, so effectively a 2 column table (with additional path metadata if need be) that has up to 7 rows per account seems out of the question.

The Model. It's easy enough to create 7 model attributes as null / set them to a string, but I'm not sold as to whether this really enforce the business logic anywhere, if anything "enforcement" is a side effect of the ORM. Like enforcing no more than 2 school children in a shop at any given time by simply reducing the available floor space.

The controller, I could reject any request to persist more than 7 pieces of information. Again this seems like more enforcement based approach than the other options.

Or all of the above, but this seems like overkill, and less maintainable if the number 7 changes up or down over time.

  • Your requirments is not clear to me : What is the final goal of that functionnality ? Letting customers creating their own data sets with their own fields ? Be able to perform searchs on it ? And you just want to limit it to 7 fields maximum ? – Walfrat Oct 24 '17 at 15:10

In my opinion, this is something that you definitely want to manage in the model but not in the way you describe.

  1. View/Controller - I tend to think of these as one thing. Even if you don't have this today, if you ever need another way to interact with your model, you have the risk of discrepancies across interfaces.

  2. You could do it here by either denormalizing the structure or with triggers. The former is undesirable and the latter is just, no, don't. You'll regret it.

The model is the best place for this because it's where your business rules and validations should be implemented. I wouldn't hardcode 7 attributes, though. I would put in a validation check that says there are no more than 7 (different) items in this collection of pages.

Based on your explanation of the reason for why 7 is the magic number, I would even more strongly recommend not using database structure or even code structure for this. I'll trust that the analysis thus far is correct and 7 is right. But the facts that this analysis are based on are not set in stone. Policies and penalties change and you might find that in a year, 5 is now the correct number. Another factor that may or may not be relevant here is that we often start with some rule or constraint that is simple and we can use data structures to implement it but later we realize that things were not that simple and the structural approach is no longer adequate. For example, lets say you expand your footprint to a different platform where the limit is different or you have a path that you don't want to count towards the limit. There's no relevant limit to the kind of complexity you can implement in rules defined in your model layer but what you can define in structure is pretty minimal.

  • 1
    7 pages is our absolute top end from various bits of research, trial and error and playing dumb on the phone for not mitigating duplicate content penalties whilst still getting recognition of structured data for improved SERPs. But we don't want to have to deploy the code to 7 different pages / templates, instead stick this widget in the footer, make the request and if its a whitelisted path on the account domain. Jobs a good'un inject the schema.org JSON-LD. – Luke Oct 24 '17 at 13:09
  • 1
    @Luke: You still don't want a fixed number of slots. It's very rare to find a quantity like this that is absolutely bounded. I suppose medal types in the Olympics (there are only 3) might be an exception, but what if the Olympic Committee decides to start handing out participation trophies? – Robert Harvey Oct 24 '17 at 14:56
  • OK what if a basic subscription tier package allowed a maximum of 5 user accounts? Is it not worth enforcing a business rule just incase one day you might want that business rule to change ? – Luke Oct 24 '17 at 20:27
  • 1
    @Luke You adequately addressed my question about why you were doing this which is why I removed it from my answer. Neither Robert nor I are suggesting that you don't enforce the constraints. I am arguing that enforcing them in the domain layer using logic instead of structure will give you the most flexibility and the best long-term results. This assumes that nothing is bypassing your domain layer, however. See Robert's answer around 'onion' architecture. – JimmyJames Oct 24 '17 at 20:57

In your proposed architecture:

Database <--> Model <--> Controller <--> View

The enforcement of your validation rules takes place in the Model. The Model is where all of your business rules are located, including any validation that must take place on your entity objects.

More specifically, your model expands to:

Database <--(SQL)--> DAL <--(CRUD)--> BLL/SL <--(DOMAIN METHODS)--> Controller

Where the DAL is your Data Access Layer (that converts SQL into CRUD methods), and BLL/SL is your Business Logic Layer/Service Layer. The BLL/SL is where you enforce your constraints via validation.

You can also enforce this particular data model constraint in your database using database triggers, capturing upstream any validation errors (or exceptions) that occur. The trigger will check whether or not 7 attributes already exist on the entity, and cancel the insert if they do.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.