I'm working on implementing a RESTfull API for my web application and it's in php. I have faced a problem on deciding whether it's recommended to create multiple different type of objects using single POST call is allowed. My scenario is as follows.
addEmployee api service function allow clients to create an employee inside my application by passing the data as POST parameters.
There are two dependencies for Employee in my system as Job Title and Employment Status and those are separately saved objects within the system. So client has to pass Job Title name and Employment Status name along with the addEmployee POST call.
When a client calls addEmployee method, it internally checks whether given Job Title and Employment Status are already there in the system and if so it only add a reference for those existing objects within the Employee object.
If given Job Title or Employment Status is not there in the system, addEmployee method will first save Job Title and Employment Status objects in the system and then will add a references in the Employee Object.
There are separate API functions for addJobTitle and addEmploymentStatus which can be used by client if they need to add more Job Titles and Employment Statuses to the system.
In the above workflow I'm not sure whether 4th step is correct because the internal saving operation is not visible to client and it reduce the visibility of the API. But usability wise it's good because client can add an Employee with maximum one web service call.
I can replace the 4th step as follows to improve the visibility.
If given Job Title or Employment Status are not there in the system, addEmployee method will return an exception saying those are not available in the system and along with that response will provide uris to addJobTitle and addEmploymentStatus functions allowing clients to use uris and save those Job Titles and Employment Status first. After saving Job Title and Employment Status objects client can again call addEmployee method to add the employee with given Job Title and Employment Status.
2nd approach will improve the visibility of the API but performance vise and usability vise it will not be much effective because client has to call API 3 times maximum to add an Employee to the system.
Please advice me what is the approach I should follow to resolve this issue.
I think the 4th step you are attempting is valid without any changes and also is the recommended approach.
If you consider Job Title and Employment Status, both of them are related to the Employee
The best approach is that you don't expose methods in your API to add Job Title and add Employment Status. Because if you do the client can keep on creating those for example one can create Job Title Software Engineer and another can create SW Engineer. Before you know it you have hundreds of Job Titles. Same applies to Employment Status.
Only Listing methods for Job Title and Employment Status may suffice with backend provisioning of those (SQL or Manual Insert or Admin only insert)
Finally as you mentioned you can reduce the multiple calls and reduce bandwidth which is crucial if the API is to be used by for example Mobile Apps over Wireless Networks.
Related
Consider the example use case as below.
You need to invite a Company as your connection. The sub actions that needs to happen in this situation is.
A Company need to be created by adding an entry to the Company table.
A User account needs to be created for the staff member to login by creating an entry in the User table.
A Staff object is created to ensure that the User has access to the Company by creating an entry in the Staff table.
The invited company is related to the invitee company, so a relation similar to friendship is created to connect the two companies by creating an entry in the Connection table.
An Invitation object is created to store the information as to who invited who onto the system, with other information like invitation time, invite message etc. For this, and entry is created in the Invitation table.
An email needs to be sent to the user to accept invitation and join by setting password.
As you can see, entries are to be made in 5 Tables.
Is it a good practice to do all this in a single API call?
If not, what are the other option.
How do I maintain data integrity if it is to be split into multiple APIs?
If the actions need to be atomic, then it's definitely best to do this in a single API call. Otherwise, you run the risk of someone not completing all the tasks required and leaving the resources in a potentially conflicting state.
That said, you're not updating a single resource, so this isn't a good fit for a single RESTful resource creation call (e.g., POST /companyInvitations) -- as all these other things being created and stitched together might lead to quite a bit of confusion.
If the action you're doing is "inviting a Company", then one option is to use Google's "custom method" syntax (POST /resources/1234:action) as defined in AIP-136. In this case, you might do POST /companies/1234:invite which says "I want to invite Company #1234 to be my connection".
Under the hood, this might atomically upsert (create if resources don't already exist) all the right things that you've listed out.
Something to consider when approaching an API call where multiple things happen when called, is how long those downstream actions take. Leaving the api call blocked isn't the best idea in the world while things are processing in the background.
You could consider (depending on your usecase) taking in the api request, immediately responding with a 200 status, and dropping the request onto an internal queue for processing. When your background service picks up the request it can update whatever needs to be updated and manage the transactions appropriately etc. This also caters for horizontal scaling scenarios where lots of "worker" services can be deployed to process the requests.
As part of this you could consider adding another "status" endpoint where requests can be made to find out how things are going. To avoid lots of polling status requests you could also take in callback details as part of the original api call which then gets called when the background processing is complete. Or you could do both!
I'm building an Angular 11 web app using AppSync for the backend.
I've mentioned group chat, but basically I have a feature in my app where I have an announcement feature where there's a person creating announcements to a specific audience (can be individual members or groups of members) and whenever the receiving user opens the announcement, it has to mark that announcement as read for that user in their UI and also let the sender know that it has been opened by that particular member.
I have an idea for implementing this:-
Each announcement needs to have a "seenBy" which aggregates the user Ids of the ones who open it.
Each member also has an attribute in their user object named "announcementsRead" which is an array of Ids of the announcements that they have opened.
In the UI when I'm gathering the list of announcements for the user, the ones whose ID don't belong in the member's own announcementsRead array, will be marked as unread.
When they click on it and it is opened, I make 2 updates - a) To the announcement object I simply push the member's user ID to the "seenBy" attribute and push to db. b) to the member's user object, I add the announcement's id to the "announcementRead" attribute and push it to the DB.
This is just something that I came up with.
Please let me know if there are any pitfalls to this approach. Or if there are simpler ways to achieve this functionality.
I have a few concerns as well:-
Let's say that two users are opening an announcement at the same time, and the clients try to update the announcement with the updated seenBy containing the user's ID, what happens when the two requests from two different clients are happening concurrently? It's possible that the first user fetches the object and then the second user fetches it immediately, and by the time the second user has updated the attribute and sent it back to the DB, the first user has already written their updated data. In such a case the second user's write to the DB will overwrite the first user's change. I am not sure of the internal mechanisms of the amplify data store, but I can imagine this happening. Is this possible? If so, how do we ensure that it is prevented?
Is it really necessary for me to maintain the "announcementsRead" attribute in the user? I mean I can imagine generating that list in the UI every time I get the list of announcements by checking if the current user's ID exists in the announcement's "seenBy" and maintaining that list in the UI, that way we can eliminate redundancy of info in the DB and also it would make sense to not accumulate extremely old announcement IDs that may have been deleted. But I'm wondering if having this on the member actually helps in an indispensable way.
Hope my questions are clear.
I'm trying to know whether there is a standard way to auto extend a Maximo contract at due date. In most Maximo contract application, there are fields to set up auto extend but there is not any cron task to handle such purpose. Do I really have to create a custom cron task and script for such purpose? Share with me you experience.
You might want to consider implementing an appropriate Escalation which could check for appropriate contracts with a due date occurring within a defined time period based on the current date (e.g. due date occurs within the next 5 days -> duedate between getdate() and getdate() + 5)
Typically we have used this type of logic in conjunction with a communication template to send an email to the appropriate party who then manually reviews and updates the appropriate contract. But you could add an appropriate action to the escalation to increment the due date by an appropriate amount + also send out the associated email to notify the appropriate parties of the implemented update?
Escalations are coded within the Escalations application, the actions application (target actions) and the communications template application (email template)
:)
I have an event sourced system that runs on a server with clients that need to work offline from time to time. To make this work I have the domain events streamed from the server to the client when online so that the offline database is up to date in case the client goes offline. This works just fine.
When offline the user might add a new customer with the following sequence...
Add new customer command.
Customer aggregate added.
Customer aggregate creates initial appointment aggregate.
Query of read data returns new appointment details.
Command used to modify the appointment.
When back online I cannot reply the events for the server. Adding the new customer is fine but the resultant new appointment has an identifier I do not know about. So trying to replay the appointment update command fails because I have no idea what the correct appointment id should be.
Any ideas?
You need to review Greg Young's talk CQRS, not just for server systems.
Also Stack overflow question Occasionally Connected CQRS Systems, and the dddcqrs topic Merging Events in Occasionally Connected Clients.
I have no idea what the correct appointment id should be
Generate the ids when you generate the commands; you'll know what the appointment id is going to be, because you told the customer aggregate what id to use when creating the appointment.
I'am trying to model hotel room booking system in actor pattern. just for information i'am using akka.net for this in .Net.
For now i have created following actors.
1. HotelActorRoomsActor (An Aggregate of RoomActor)
3. BookingsActor (An Aggregate of BookingActor)
4. EmployeesActor (An aggregate of EmployeeActor)
4. UIActor
Currently as i have planned iam creating the system as follows.
1. UIActor Takes the BookingInformation (Checkin, Checkout, No of rooms)
2. Tell the BookingsActor about the information.
3. BookingsActor creates / starts a new BookingActor and passes on the information
4. On BookingActor Start it will
4a. Schedule Rooms for the Booking
4b. Tell the Rooms about the schedule so that they block themselves
4c. Schedule Employee Tasks for the rooms
4d. Tell the selected employees about their tasks
4e. Tell the system that the booking as been created
4f. Tell the BookingsActor to restart the BookingActor at some specific time in
the future (24 hours before actual booking checkin) and shut down.
Problems im facing are
1. How to keep the UIActor in sync of the booking information
2. The UIActor Should also be able to Save information about multiple bookings (For a partiular customer etc) how and where should it be done inside an Actor Pattern?
3. Lets say i want the information about multiple bookings From Date1 to Date2 where should i persist this information to later retrieve it?
ad 1. you can see example of sync dispatcher in akka bootcamp
and example source:
dispatcher = akka.actor.synchronized-dispatcher
#causes ChartingActor to run on the UI thread for WinForms
ad 2. the UI actor should only collect data from user and display results, all other actions need to be pushed down for processing to let say storage actor
ad 3. you need a storage provider - that can be mongoDB or SQL solution. Passing a message to storage actor you can persist reservation data or retrive when needed.