GraphQL: Modeling evolving types / state transitions - api

This is an issue we have ran into multiple times now... very much looking forward to others' opinions!
Scenario Description (for illustration purposes):
Somebody visits our website, perhaps they fill out some forms, whatever. To us, this person is a prospect/lead. They have not been fully onboarded as a customer; they are simply a potential future customer.
Certain actions can be performed on these Prospects, such as adding certain data to their profile. Let's call this add_foobar_data. Of course, if they become a real customer (somebody consuming our service), we still need to be able to add/remove said data from their account.
Scenario (tl;dr):
Prospects can become Customers
Mutation add_foobar_data conceptually applies to both Prospects and Customers
Prospects only have a subset of data of Customers (they are a true subset; currently Customers have a lot of non-nullable fields Prospects do not have)
Options:
Create a union type, e.g. Customerable. add_foobar_data would return a Customerable (or backref to a Customerable) rather than a specific type.
Create separate mutations for modifying Prospects and Customers (add_foobar_data_to_prospect, add_foobar_data_to_customer)
Everybody is a Customer! Make all those non-nullable fields on Customer that are not in Prospect nullable and add a new flag called isProspect (or isDraft if we want to change how we think about the flow).
Perhaps some other approach I did not think of...
Anybody have thoughts on what is the best approach to this situation and why?

Ended up using an Interface since Prospect is a direct subset of Customer, and not by coincidence.

Related

Best practice regarding encapsulation and single responsibility design

I've been developing for many years and a common problem I face is how best to separate out the service layer. I've been using the repository pattern mainly, but I still struggle with this common scenario.
Customer service that returns a single customer.
Invoice service that returns a list of invoices by customer.
The consumer of the service sometimes wants just a Customer other times they want the customer and the invoices which is fine to leave as two calls.
But a new requirement may be they want the Customer, but also want the total number of invoices the respective customer has.
I do not want to corrupt the GetCustomer method and do not want to return a list of invoices and have them do a count (this would work). Is there a best practice without getting into create a lot of one of methods while still keeping performance and round trips in mind? I see a lot of designs where there will get GetCustomer, GetCustomerDeepLoad, etc.
thanks.
It's simple. Don't overthink it.
Services need to meet the needs of the clients. If the client wants customer details, the service sends a representation of customer details and nothing more; if the client wants a customer and all their orders, the service obliges; and so on. In doing so, you might need more than just a Customer object; for example, you might need a CustomerOrderList object made up of CustomerOrderItem, etc.
What you MUST NOT do is mix the concerns of order management and customer management, meaning that the CustomerOrderItem that you return will be a version suited for customer management and not the full-fledged OrderItem that would be modelled for order management.
That's the reason why I have switched to CQRS. Operations (writing/commands) often targets a single entity type while reads (queries) often want a composition of entities.
You dont want to get those queries into the repositories as the repositories tend to get leaky abstractions when you do that.
In your case you can have two types of services: Entity services which are responsible of taking care of changes and query services which are responsible of taking care of supplying information to the client (composition of different entities).
I typically use repositories only on the write side and let the query services query the database directly. That works as you have your business logic contained in the entity services.

Vendor specific pricing on Shopify

A client of mine has a service-oriented ecommerce site on Shopify and he's asked me to assist in making a few changes. I've never utilized the service so I'm not really familiar with it.
The price list was static at first since the client used the same vendor however now that they're growing - and therefore using multiple vendors - the costs are fluctuating and therefore the prices on Shopify need to reflect that.
I need to set it up so that when a customer logs on a vendor is programmatically chosen based on their geographic location and the prices (shown to the customer) adjust accordingly.
Is this possible? And if so, what objects/API docs should I be looking at. I seems as if I can easily hard code this with IF statements but I'd like this to scale cleanly so I'm looking for a more efficient solution.
I think this should be possible. Based on your comment:
Will I not have a zip code for the customer? – RyanMac
The easiest way would be to create a Product Variant for each region. Based on the customer.default_address you could find the customers ZIP code. Next step would be to use this within the product.liquid template to select the correct variant.
The biggest problem you have is determining their location. When a customer logs in, you know who they are, so you could dish out only products of interest to them. Problem is, how do you lump people into those regions? You have your work cut out there. When you create a customer you can assign them any code you want, so perhaps you could just match customers to vendors using a match on that. Lump any customers into GroupA and you show only products with Vendor GroupA, any customers assigned to GroupB render products from vendor GroupB....etc

"Dynamic" Pricing System

Soon I'll be working on a project that amounts to what is essentially an e-commerce app for configured products. This question is about ways to implement pricing schemes that can change from day to day, so we want to get the pricing logic out of code and into a database, but not in a way that causes the database to do all the work.
The basic idea is this, there are 5 attributes. You pick an option from each of those attributes. Then you start adding products to your cart. All the product you add will have those 5 attributes tacked onto them (the attributes will affect the pricing). Once you've added a product, you can apply modifications to it (the attributes will also be applied to the modifications).
So, what we've got at this point is a product (which has a fixed base price) with some information about it (that will modify the price), and zero or more modifications (which has a fixed price) and some information about them (which will modify the price). Modifications can also incur additional charges. For instance, if company A uses this software and they price their items using: BASE_PRICE + $50 * NUM_WHIRLIGIGS and the item has a modification that adds a WHIRLIGIG, that will have to be reflected in the price.
Do you know of any examples of different pricing systems that I might find useful when determining how to set this up? Do you have better ideas?
My current best thought is below, you can skip it if you're not curious about the particulars of the method and just want to get right to the answering!
For any given item (or collection of items) the company could use a special interface to set up pricing formulas which would then be interpreted and evaluated at run-time.
So for PRODUCT_A, the company might put in something like BASE_PRICE + WHIRLIGIG_UPCHARGE * NUM_WHIRLIGIGS. And the software, when it comes time to price it, would look at how many WHIRLIGIGS the item has, as well as how many WHIRLIGIGS are added by any modifications.
Does anyone have experience implementing this kind of interpreter? How did it turn out? Was it difficult/troublesome?
Thanks in advance for all the awesome input I'll sure I'll get. :P
Typically, this is usually handled with product bundles which have components. So a product with 5 additional subcomponents would not be base + 5 * addon, but SUM(base, addon, addon, addon, addon, addon).
So your product table may either be self-referential or there is some kind of link table which says which sub-products are allowed to be attached to which products.
In my experience, pricing is usually stored on a product/customer or contract basis, so that's another table.
Then the actual orders themselves contain product bundles. If the order is a quote, then the pricing is frozen (up to the expiration of the quote).
When an quote or order is turned into an invoice, at that time the pricing is either locked in from the main pricing or the quote, depending upon the pricing timing paradigm.

Typical normalization security issue in web applications

i am currently having a problem, i guess a lot of people have run into before and i would like to know how you handled it.
So, imagine you have 10.000 Users on your App. ( each one has an own user/pw login to administrate his stuff ).
Imagine further, that you have a growing normalized SQL-tablestructure in the backend, with tables like: Users, Orders, OrderPositions, Invoices, etc.
So, to show/edit/delete stuff of a table which isn't the usertable itself, u'll probably have links like these, to let ypur users interact with the application.
~/Orders/EditOrder?id=12
~/Orders/ShowOrderPosition?orderId=12&posId=443
Ok, and now the problem:
How, do i prevent in a "none-complex"-way, that user A has access ( show/edit/delete ) the data of user B.
Example:
User B calls:
~/Orders/ShowOrderPosition?orderId=12&posId=443
which is an order of user A, so user B should have no access to it.
So, in my code i would need to have a UserIdentity-check before or within every single SQL-statement, like:
select * from OrderPosition op, Order o, User u
where op.Id = :orderId
and op.Fk_OrderId = :orderpositionId
and o.Id = :orderId
and o.Fk_User = :userId
Only this way i can make sure, that the data belongs to the requesting user.
To reach the usertable will of course get far more complex, the deeper the usertable-connection is "buried" in the normalization ( imagine tables like payments or invoices, connected to the order-table... )
Question:
What is your approach to deal with this, concidering: Low complexity, DRY and performance
( Hope u understand what i mean ;) )
This is a bit like a multi-tenant application - I have gone down this route and denormalized an ID onto all those tables that require this kind of check (a tenant ID, in your case, sounds like the user id).
I then created an interface that contains this field only and applied it to all those classes in my model layer that required this access.
In my base data access (repository) class, where all the select/update/delete calls go through, I then check to see if the class if of the type of that interface, and I then check that the current access matches that ID.
Of course, this depends on how your code is structured, and how simple/complex making this global kind of change will be...
Never expose ids.
And if you have to: encrypt them.
Performance
for ultimate performance you will have to denormalize to the point that reading the row and comparing with some application level variable would give you an answer on what kind of rights the user has (this is fairly fast and if your DAO/BAO level is well organized plugging it in will keep it relatively DRY and at relatively low complexity.) NOTE: complexity is also a function of your security model, once you start to implement inheritable, positive and negative, role-based access rules then it can not be really simple.
DRY
another route to take (which is very seldomly taken these days) is to use your database roles to manage security; this might get complicated but will offer unparalleled security (as it will be ensured at the DB level and not application level. Complexity should go down, at the application code level, if you manage to encapsulate all of your access paths into VIEWS, which might require quite a bit of re-tailoring at the database level. However(!), it might be possible to implement security model with very little changes to the application code - by renaming existing tables and replacing them with secured views)
Don't use your internal ID column, encrypted or not, it'll come back to bite you one day.
Create a random, unique, string (GUID, whatever), which contains the link between the user and the data he's requesting. So, instead of having, for user 34567:
Edit order
Create a record {"5dsfwe8frf823jrf",34567,12} in a temporary table and show:
Edit order
When the users clicks the link, fetch 34567,12 from your temporary table.
The string 5dsfwe8frf823jrf is impossible to guess = no security risk.

Data Mapper API - unsure about organisation

Let's say we have "User" and a "Hotel" model classes. I'd use a User_Mapper and Hotel_Mapper to load/save/delete etc. I want to then have the user be able to mark their "favourite" hotels. In the database I have my user_favourite_hotels table which is a simple link table along with say a field for subscribing to hotel updates.
When listing out the user's favourite hotels, how would you expect this to work from an API point of view? A part of me thinks that this should be a "findFavouritesByUserId" method on the Hotel_Mapper, but other than saying it "feels" right - however a colleague suggests that the "favourites" is owned by the user and should therefore be on the User_Mapper.
Perhaps I should have a User_Hotel_Favourites_Mapper? I was thinking of incorporating the "favourites" data in to the User object so it's saved and loaded whenever the User object is. I'm not sure whether it'd be better to split it out in to it's own object and mapper however.
I'd appreciate any advice on how best to setup the API for the above and any pros/cons/experiences.
Thanks very much,
James.
This (admittedly retired) patterns&practices guide to designing data tier components suggests that you put the method in the mapper of the type of object that you're getting back from the call.
If you have methods that return a particular type of business entity, place these methods in the Data Access Logic Component for that type. For example, if you are retrieving all orders for a customer, implement that function in the Order Data Access Logic Component because your return value is of the type Order. Conversely, if you are retrieving all customers that have ordered a specific product, implement that function in the Customer Data Access Logic Component.
So, in your example, it would go in the Hotel Mapper as it is returning Hotels.
If you want to store favorite hotels for the user, you are using the UserMapper, which notices that domain object for User has changes favorites, and updates both tables for users and for user_favorite_hotels ( you just need the hotel IDs ).
When you are retrieving favorite hotels of some user, you use HotelMapper and set filter to be based on User, because you will be working with instances of Hotel.
Considering that this was asked more than 2 years ago, I'm not sure if an answer matters to you now. But here's what I think anyway.
If User could have multiple types of favourites (including Hotels), it may make sense to have a UserFavourites abstraction to cover all possible types of favourites. UserFavourites could expose a getItems() method to get the underlying Favourites.
This could be managed with the help of a manager class to return the appropriate Favourites object(FavouriteHotels for example) on which the getItems() method can be called.