Writing a REST API for Complex Nested Data

2020-06-23 09:32发布

问题:

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.

  1. Doctors (each doctor may have multiple patients)
  2. Patients (each patient may have multiple doctors)
  3. Appointments (appointments exist for doctors, naturally)
  4. 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.

  1. Each doctor must be able to request for all his patients or a particular one.
  2. Each patient must be able to request for all his doctors or a particular one.
  3. 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.
  4. 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.
  5. Each doctor must be able to request for all appointments from a single patient.
  6. Each patient must be able to request for all his appointments from a single doctor.
  7. 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.

  1. /doctors/
  2. /doctors/:id
  3. /doctors/:id/patients (returns a list of /patient/:id)
  4. /doctors/:id/appointments
  5. /patients/
  6. /patients/:id
  7. /patients/:id/doctors (returns a list of /doctors/:id)
  8. /patients/:id/appointments

Now, I'm okay with the ones above. Here are my questions.

  1. How do I design a URL for task number 7 without having nesting like /doctors/:id/patients/:id/appointments?
  2. 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.
  3. Also, what about appointments to see a particular patient or a particular doctor?
  4. And what about appointments for each doctor or patient on a particular date?

I feel like too much nesting is going on. Please help.

回答1:

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.



回答2:

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