Writing a REST API for Complex Nested Data - node.js

So, I'm building an application in Angular which would leverage a REST API at the back, running on Node. I'm having some trouble handling the data complexity while designing this API and could use some help.
Here are the different resources, in question.
Doctors (each doctor may have multiple patients)
Patients (each patient may have multiple doctors)
Appointments (appointments exist for doctors, naturally)
Reminders (reminders may be sent from doctors to patients, not the other way around)
Now, here are some of the operations that the application may carry out, so the requirements from the API are clear.
Each doctor must be able to request for all his patients or a particular one.
Each patient must be able to request for all his doctors or a particular one.
Each doctor must be able to request for all his appointments (to see all patients) for a particular date, or for all days, if necessary.
Each patient must be able to request for all his appointments (to see all doctors) for a particular date, or for all days, if necessary.
Each doctor must be able to request for all appointments from a single patient.
Each patient must be able to request for all his appointments from a single doctor.
Each doctor must be able to request for all his reminders to a particular patient.
Remember, the request could naturally be a POST, GET, DELETE or PUT. Now, here is where I am so far. I'm only mentioning the URL, the operation on each when sent a POST, GET, DELETE or PUT is self-explanatory.
/doctors/
/doctors/:id
/doctors/:id/patients (returns a list of /patient/:id)
/doctors/:id/appointments
/patients/
/patients/:id
/patients/:id/doctors (returns a list of /doctors/:id)
/patients/:id/appointments
Now, I'm okay with the ones above. Here are my questions.
How do I design a URL for task number 7 without having nesting like /doctors/:id/patients/:id/appointments?
Also, I can get all appointments for a doctor or for a patient quite easily with the above. What about particular appointments? /doctors/:id/appointments/:id or /patients/:id/appointments/:id doesn't feel quite right.
Also, what about appointments to see a particular patient or a particular doctor?
And what about appointments for each doctor or patient on a particular date?
I feel like too much nesting is going on. Please help.

Your list of endpoints looks good. I guess there can be different opinions about what you asked.
The following are my opinions about what could be done:
How do I design a URL for task number 7 without having nesting like /doctors/:id/patients/:id/appointments?
I would suppose a collection of reminders would exist and define it as follows:
/doctors/:doctorid/reminders
/doctors/:doctorid/reminders/:patientid
Also, I can get all appointments for a doctor or for a patient quite easily with the above. What about particular appointments?
/doctors/:id/appointments/:id or /patients/:id/appointments/:id
doesn't feel quite right.
There is no need to complicate the endpoints to that level. If you already know the appointment id why would you reach it through the doctors or patients endpoints? It does not not matter, you reach the item directly through its collection.
/appointments/:appointmentid
Also, what about appointments to see a particular patient or a particular doctor?
You can leverage the power of query parameters for this kind of thing. Not everything has be part of the URL template. Features like filtering of specific records could be added to the query parameters instead. For instance
/doctors/:doctorid/appointments?pantientName=
/patients/:patientid/appointments?doctorName=
And what about appointments for each doctor or patient on a particular date?
Same thing here, you could something like:
/patients/:patientid/appointments?from=&to
Or have special endpoints for very well know cases like, my appointments for today, for this week, for this month:
/patients/:patientid/appointments/:year
/patients/:patientid/appointments/:year/:month
/patients/:patientid/appointments/:year/:month/:day
These latter could actually reuse the same logic used to implement the one getting appointments between a range of dates.

The URI structure is not a REST concern, because according to the uniform interface constraint it has to be decoupled from the client.
What matters:
A specific URI (including the path and the query) can identify only a single resource.
The URI is mapped to the resources and not to the operations, so if you use human readable nice URIs, then they will contain only nouns.
How do I design a URL for task number 7 without having nesting like
/doctors/:id/patients/:id/appointments?
You can map reduce the existing appointment collection, like so:
/appointments?doctor=1&patient=1
/appointments/doctor:1/patient:1
And what about appointments for each doctor or patient on a particular
date?
You can use a date filter to do that:
/appointments?date=2014-09-02
/appointments/date:2014-09-02

Related

How to ensure data consistency between two different aggregates in an event-driven architecture?

I will try to keep this as generic as possible using the “order” and “product” example, to try and help others that come across this question.
The Structure:
In the application we have 3 different services, 2 services that follow the event sourcing pattern and one that is designed for read only having the separation between our read and write views:
- Order service (write)
- Product service (write)
- Order details service (Read)
The Background:
We are currently storing the relationship between the order and product in only one of the write services, for example within order we have a property called ‘productItems’ which contains a list of the aggregate Ids from Product for the products that have been added to the order. Each product added to an order is emitted onto Kafka where the read service will update the view and form the relationships between the data.
 
The Problem:
As we pull back by aggregate Id for the order and the product to update them, if a product was to be deleted, there is no way to disassociate the product from the order on the write side.
 
This in turn means we have inconsistency, that the order holds a reference to a product that no longer exists within the product service.
The Ideas:
Master the relationship on both sides, which means when the product is deleted, we can look at the associated orders and trigger an update to remove from each order (this would cause duplication of reference).
Create another view of the data that shows the relationships and use a saga to do a clean-up. When a delete is triggered, it will look up the view database, see the relationships within the data and then trigger an update for each of the orders that have the product associated.
Does it really matter having the inconsistencies if the Product details service shows the correct information? Because the view database will consume the product deleted event, it will be able to safely remove the relationship that means clients will be able to get the correct view of the data even if the write models appear inconsistent. Based on the order of the events, the state will always appear correct in the read view.
Another thought: as the aggregate Id is deleted, it should never be reused which means when we have checks on the aggregate such as: “is this product in the order already?” will never trigger as the aggregate Id will never be repurposed meaning the inconsistency should not cause an issue when running commands in the future.
Sorry for the long read, but these are all the ideas we have thought of so far, and I am keen to gain some insight from the community, to make sure we are on the right track or if there is another approach to consider.
 
Thank you in advance for your help.
Event sourcing suites very well human and specifically human-paced processes. It helps a lot to imagine that every event in an event-sourced system is delivered by some clerk printed on a sheet of paper. Than it will be much easier to figure out the suitable solution.
What's the purpose of an order? So that your back-office personnel would secure the necessary units at a warehouse, then customer would do a payment and you start shipping process.
So, I guess, after an order is placed, some back-office system can process it and confirm that it can be taken into work and invoicing. Or it can return the order with remarks that this and that line are no longer available, so that a customer could agree to the reduced order or pick other options.
Another option is, since the probability of a customer ordering a discontinued item is low, just not do this check. But if at the shipping it still occurs - then issue a refund and some coupon for inconvenience. Why is it low? Because the goods are added from an online catalogue, which reflects the current state. The availability check can be done on the 'Submit' button click. So, an inconsistency may occur if an item is discontinued the same minute (or second) the order has been submitted. And usually the actual decision to discontinue is made up well before the information was updated in the Product service due to some external reasons.
Hence, I suggest to use eventual consistency. Since an event-sourced entity should only be responsible for its own consistency and not try to fulfil someone else's responsibility.

Is an order something transient or not

In my company (train company) there is a sort of battle going on over two viewpoints on something. Before going to deep into the problem I'm first going to explain the different domains we have in our landscape now.
Product: All product master data and their characteristics.
Think their name, their possible list of choices...
Location: All location master data that can be chosen, like stations, stops, etc.
Quote: To get a price for a specific choice of a product with their attributes.
Order: The order domain where you can make a positive order but also a negative one for reimbursements.
Ticket: This is essentially what you get from paying the order. Its the product but in the state that its at, when gotten by the customer.
The problem
Viewpoint PURPLE (I don't want to create bias)
When an order is transformed into all "tickets", we convert the order details, like price, into the ticket model. In order to make Order something we can throw away. Order is seen as something transient. Kind of like the bag you have in a supermarket. Its the goods inside the bag that matter. Not the bag itself.
When a reimburse flow would start. You do not need to go to the order. You would have everything in the Ticket domain. So this means data from order will be duplicated to Ticket.
But not all, only the things that are relevant. Like price for example.
Viewpoint YELLOW (I don't want to create bias)
You do the same as above but you do not store the price in Ticket domain. The ticket domain only consist of details that are relevant for the "ticket" to work. Price is not allowed in there cause its a thing of the order. When a reimburse flow would start, its allowed to go fetch those details from the order. Making order not something you can throw away as its having crucial data inside of it.
The benefit here is that Order is not "polluting" the Ticket with unnecessary data. But this is debatable. The example of the price is a good example.
I wish to know your ideas about these two viewpoints.
There is no "Don't repeat yourself" when it comes to the business domain. The only thing that dictates the business domain is the business requirements. If the requirements state that the ticket should work independent of the order changes, then you have to duplicate things.
But in this case, the requirements are ambiguous. There is no correct design using the currently specified requirements. Building code based on assumptions is the #1 way of getting bad code, since you most likely will have to do a redesign down the road.
You need to go back to the product owner and ask him about the difference between the Order and the Ticket.
For instance:
What should happen to the ticket if the order is deleted?
What happens to the order and/or ticket if the product price changes?
What happens to a ticket if the order is reimbursed?
Go back, get better requirements and then start to design the application.

Calculate datetime between client and server (Node JS)

I have an application that uses subscriptions for each member that joins. I'm having some issues with dates and calculations related with it. For example, let say a member joins on 2/10/2020 at 10:00. When the user submit the request to the server to process the subscription (the server is using UTC) the date that is being calculate is 2/10/2020 16:00 (because I'm -6:00 hours from UTC). This scenario is OK at this point, because the date is still the same (no matter the time). But, if we replicate this scenario when the user joins for example 2/10/2020 at 19:00, when the request is received and calculate the date, the result is 2/11/2020 01:00, and that produces an error in the invoice because the billing date of the invoice is wrong (one day after). What is the best way to implement this? I have read a lot of this topic, but most of the pages and questions are related in the other way, server to client, to parse of format dates to display to the user.
I have several questions related with this process.
Should I sent the date for the UI to the API? Or the timezone and
based on that, calculate the date in the API? (since the server have
UTC)
Moment.js library have a way to solve this or should be better with vanilla Javascript using Date?
Is there any HTTP header for the request to handle the time or date?
This really depends on what behavior you want to have. Before you try to fix anything, think through and decide on the exact requirements for what the billing date should be based on.
Is the user's time zone relevant? If so, you'll likely need to know what the user's time zone is. You'll be potentially assigning different dates to different invoices even if they're using the same UTC point in time. Your business might get confused on why some customers have invoice dates before or after the business day.
Or maybe the time zone of your company is more relevant? Many business work that way. All of your invoices will be aligned, but some customers might get confused on why their invoice date is before or after their current date.
Or maybe some customers snap to time zones of nearby offices, in the case of businesses with offices around the world.
Only you and your company can decide this. There are probably other options I'm not thinking through here. It's a business decision, not a technical one.
On your three questions:
That depends on what you decide above.
Libraries are a good idea for simplifying your code, but they're not a hard requirement. You can use the Date API, if you know what you're doing, but you may find libraries easier to work with. Also, Moment is in maintainance mode. For new development, the Moment team recommends you use Luxon instead of Moment. There are other popular modern libraries also, including date-fns and js-Joda.
There's the date header, but that's not going to help you with this.

Context level DFD

So, not really sure if this is the right place for this but I have this current Context level data flow diagram for the bellow specification extract and I have never done one before so I was wondering if it was correct or if it needs fixing? any help appreciated
This is a link to a screen of my current one http://i.imgur.com/S4xvutc.png
SPECIFICATION
Currently the office staff operate the following processes:
Add/Amend/Delete Membership
This is run on-demand when a new membership application is received or when a member indicates that he/she wishes to make amendments to their details. It is also run in those rare instances when a membership is terminated at the discretion of the manager. A new member has an ID number allocated (simply incremented from the previous membership accepted). A membership balance is also maintained for accounting purposes.
Another process operates in a similar fashion on data associated with transfer partners.
Monthly Maintenance
This is run on the last day of each month to issue requests and reminders for subscriptions due, and to remove memberships where fees remain outstanding. Standard letters are also generated. Membership balances are updated as appropriate.
Payment Updates
This is run prior to the Monthly Maintenance, with membership balances being updated accordingly.
Payments to partners are also disbursed at this time.
New Member Search
This is run whenever a new member has been added to the database. The partners are partitioned in terms of vehicle category and location. Normally, there is a limited choice of partner in a particular location (if, indeed, there is any choice) but for some popular destinations, several partners are involved in providing the airport transfer. Thus, a search is then made through the appropriate section for potential matches in the following manner:
A search is then made on the grounds of sex (many female passengers in particular prefer a driver of their own sex, especially if travelling alone or in couples).
Matches are then selected according to factors such as cost (if available), availability of extra requested facilities (such as child seats, air-conditioning etc.)
Existing Member - Additional Searches
These are run on-demand in the same fashion as for a new member's search. Members may of course request any number of such searches, but a separate payment is due for each.
All financial transactions (payments) are also posted to the separate Accounts file, which also stores other financial details relating to running costs for the consideration of the firm's accountants at the end of the financial year.
Thanks for any help, regarding this level 0 Context only DFD
It needs some fixing.
The most obvious flaw is that you use verbs in your dataflows. In some cases this can be fixed easily by just discarding the verb. Return balance and status is not a datflow, but balance and status is.
In others cases it is not so easy. Check Balance, is it outstanding? sounds more like a Process than a dataflow. It looks like Accounting is responsible for doing that job. So will Accounting produce a list of outstanding balances? Or will it return a single balance and status, and if so, based on what input? Will your Airpot Transport System send a list of balances to check to Accounting?
Take for example Monthly Maintenance. What matters is that you want
requests and reminders for subscriptions due
Standard letters
These need to be visible in your DFD
The fact that you want to remove memberships where fees remain outstanding, probably has not place in the toplevel diagram, because that looks like an internal affair.
In general, focus on what the System produces. Maintaining internal state is secondary, is is a necessity to produce the desired output.

Business rules integration to User Stories

I have a set of User Stories and I have a set of business rules (primarily laws binding my requirements to be compliant). In Agile SDLC I'm not sure where these "rules" are attached to my user stories.
For example, a user story like:
As a doctor I want to add patient information in order to create a new patient file.
And a rule like:
The following information must be entered in the record of each patient:
(a) patient:
(i) name and given name;
(ii) address;
(iii) date of birth; and
(iv) sex;
These two clearly come together, but how can I link them? As test acceptance definitions in my user story? Another user story?
There are a few different ways I've seen this handled:
An artifact is created to hold the business rule and is stored in some central repository of all the rules so this is known throughout the development team and a storehouse of knowledge is maintained. This can get ugly as there can be hundreds of rules within just a few years of building out an application.
The rules may be put onto separate cards within the user story. Thus, while the user story is that one line, there may be 6-8 cards that make up all the tasks for that story to be completed. For example, there has to be a new patient form created, validation on the form, etc. Thus, it isn't hard to see this crop up down the line on a card as a way to track the requirement that way. This is the most natural to my mind though this isn't where the specific list is going to be 100% written down either as the card could be "ensure some fields on the form are mandatory."
There isn't an explicit link but rather the rule is something for QA or a BA to note for the user to verify that the form does enforce this rule. This is similar to one but the question is what is the responsibility of the developer in this. In this case, it is something for QA to track rather than developers possibly.
The user story is intended to start a discussion, not be a comprehensive list of the requirements. The rule is something that should come up when the developer discusses with the user what does it take to create a new patient file to my mind.
I like the idea of hanging on to cards for a few sprints after the story was done, but I do see the point that the cards will ultimately be destroyed. At the same time, there should be code somewhere that implements the rules in its proper area. To use the example you posted, it may be that in a few places the list of required fields would be noticed as there is the UI layer that has to show the fields and probably an error message but also there should be some Business Logic Layer that has this logic to see that some fields were specifically completed before trying to create a new patient file. The system being built will also house the rules in some form or other, too.
As acceptance criteria. After all these are rules that can be executed as tests. Definitely not new stories, that would just be wrong as there is no deliverable goal.

Resources