REST API naming confusion - how to name a resource that does an assignment? - api

I'm developing a REST API, and I've got the following tables in the DB: classes, subjects, classes_subjects; and the following resources: http://api.example.com/class resource for the classes table, and http://api.example.com/subject resource for the subjects table.
I would like to assign a subject to a class of students (e.g. assign Literature to class 1), i.e. save the class_id and subject_id in the classes_subjects table, but I've got a hard time figuring out how to name the new resource for the classes_subjects table.
I can't name it http://api.example.com/assign because that would be against REST principles, but it would also be awkward to name it http://api.example.com/classes-subjects
Should I just use the /class resource and use PUT when assigning a subject?
I can't figure out any noun to use for assigning subjects to classes. Does any of you know how to handle this kind of issue?

You can use the following schema:
Get all classes with subject 123:
GET /subjects/123/classes
Associate a class with a subject:
POST /subjects/123/classes?classId=<classId>

Related

API convention for parent -> child element calls

We are trying to figure out if there is a generally accepted way of providing an API parent -> child resource. Say we have a Person entity and each Person has 0 or more addresses represented by the Address entity.
In terms of basic API we'd have:
POST: /api/v1/person
GET: /api/v1/person/{id}
PUT: /api/v1/person/{id}
DELETE: /api/v1/person/{id}
Then we have 2 ways to retrieve the addresses for a person:
/api/v1/person/{id}/addresses
/api/v1/addresses/{personId}
We feel it's more natural to pick the former option /person/{id}/addresses for GET but at the same time if we wanna retrieve an address by its id it should be /api/v1/address/{id}.
The question is, is there a convention in dealing with POST, PUT and DELETE calls? To me it makes sense that these should be called to the address service at /api/v1/address OR /api/v1/address/{id} but at the same time I can see why someone would POST to `/api/v1/person/{id}/address' instead of passing the person id in the request body.
So yeah, can you guys point us in the right direction here - is there a written or unwritten rule in API design when it comes to parent -> child relations?
Thanks in advance!
Can an address exist without a person? If the answer is yes, then an address should be a resources of its own.
/api/v1/addresses: the collection of all addresses
/api/v1/addresses/{addressId}: a single address
/api/v1/addresses?person={personId}: all addresses for a person
I'd not use /api/v1/addresses/{personId} because it is not immediately obvious that personId is the ID of a person, not of an addresse.
But at the same time, /api/v1/person/{id}/addresses should be available to navigate from a person to all his addresses.
If an address can not exist without a person, only use /api/v1/person/{id}/addresses.

Design a RESTful API in Laravel 5.2, using a resource that conceptually can contain other resources

First of all I am really not very familiar with the REST practice, and I am not very confident about the title of my question.
So I am trying to built a RESTful API using Laravel for a phonebook application. The phonebook may contain telephones of either employees (i.e real persons) or offices. For that reason I have three models
a Directorate with id and name fields,
an Employee with id and name fields and
a Telephone with id, tel, employee_id, directorate_id, description and type fields.
Telephones corresponding to a directorate's office have only the id, tel, directorate_id and description fields set, while the telephones corresponding to a person (i.e an employee) have set only the id, tel, employee_id, directorate_id, and type fields. That is how I separate them: a telephone having a description can only be an office's telephone, while a telephone having both the employee_id and the type_id set is an employee's telephone.
The models are related as follows:
an employee may have many telephones
a directorate, may have many telephones
class Directorate extends Model
{
public function telephones()
{
return $this->hasMany(Telephone::class);
}
public function employees()
{
return $this->hasMany(Employee::class);
}
}
class Employee extends Model
{
public function telephones()
{
return $this->hasMany(Telephone::class);
}
public function directorate()
{
return $this->belongTo(Directorate::class);
}
}
class Telephone extends Model
{
public function employee()
{
return $this->belongsTo(Employee::class);
}
}
My question is what should I a consider as my resource.
So far I am thinking of the following approach:
I shall use the concept of contact as resource. A contact may be the joined information of either an employee and a telephone, or a directorate and a telephone. For instance, a "contact" may contain the name of an employee with his related telephone numbers and telephone types, or it can contain the name of a directorate with the description of the telephone and the telephone number.
The "problem" with this approach is that I have ended up with (let's put it this way) two different types of resource: the employee's contacts and the directorate office's contacts, which contain slightly different information and thus, I need also to have different create and edit forms to interact with these two "types" of resources.
In order to implement the REST API, I am thinking of two different scenarios:
Use two different RESTful controllers, one EmployeeContacts and another OfficesContacts for separating conceptually the resource to an employee's and an office's resource, and accessing them through different URIs like:
example.com/phonebook/employees/{id}/edit
example.com/phonebook/offices/{id}/edit
example.com/phonebook/employees/create
etc...
Use a single RESTful controller, e.g. PhonebookContacts to access the resources through the same URIs as one resource (i.e. both employee's and office's contact resources now are considered to be just a "contact" resource)
//this refers to a contact resource that can be either an office's or a n employee's contact
example.com/phonebook/contact/{id}/edit
//this should list all resources (both employees and offices contacts)
example.com/phonebook/contact/
and then use conditional statements in the controller's create/store/edit/update methods to deal with them separately (e.g if an http POST request contains a description_id then it is an office contact and do this, or else if has an employee_id then it is an employee's contact so do that...)
I would like to hear your views, what of these two different scenarios do you consider to be better in the context of REST for my phonebook app? Would be better to think of a single "contact" resource and handle it using conditional statements with different return in the controller, or shall I separate the concept of "contact" to "employee's contact" and "office's contact" and use separate controllers and URI's to handle them?
Is there another approach that I could follow instead?
The way I would do it is with 2 different controllers for the simple reason of speed and responsiveness. Loading all contacts and filtering isn't as quick as loading the one part only.
However, you can always set in your controller the same return with different data. Such as EmployeeController#index returns view('contacts.index', compact('employeeContacts')), and OfficesController#index returns view('contacts.index', compact('officesContacts'))
EDIT:
Sorry, I have misread it...I thought you wanted to do the filtering in the view. Anyway, my practice is to do it separately, simply because the code is cleaner. If you want to make the whole REST more readable, you can put both resources in a group like so: Route::group(['prefix' => 'contact'], function(){ //routes here// });
So now you will have routes like:
example.com/contact/employees/
example.com/contact/offices/
I am not familiar at all with Laravel but since this question is about REST concepts (I have a small background on these) I should give it a try.
Since you are building a RESTful application, you must not consider others as human beings but only as machines. IMO the urls should determine the action that will be performed. Thus, by using different urls for different actions (perform a CRUD on a contact - either an Employee or a Directorate or SomethingElseInTheFuture) sounds good to me and fits the REST nice.
Hope this clarify the things for you!
[EDIT]
I believe jannis is right. It should be the verbs (GET, POST, PUT, PATCH etc) that make the action instead of the URLs. The urls are just respresenting the resources. My mistake. So both of your points of view are correct. It's just how convenient each approach is for your project (for now and for the near future of your project). IMO, I see #1 (two different restful controllers) more approchable.
Cheers and sorry for any misconception!

Designing a rest url - filter with multiple params over entities (not last entity)

Let's say I have the following entities in my libraries app - Library Room, shelf, Book.
Where Room has N shelves, and shelves have N Books.
Now the following url brings me a list of books whose
library is 3, room no. is 5 and shelf no. is 43.
.../library/3/room/5/shelf/43/books
Assuming shelf 43 is unique per room only
(There is shelf 43 also in other rooms)
and Rooms are not unique (There's a few room no. 5 ) in the library.
Here is my questions:
I want to filter with more fields on the entities, here is what i want to do
(representation not in rest):
.../library/id=3&type=3/room/decade=21&topic=horror/shelf/location=east&/books
This is not rest.
How do I represent it in rest?
Notes:
I don't want to do this way
.../books&param1=X&param2=X&param3=X&param4=X
because not all params are related to books.
Couple of things that you need to look into while designing your apis.
1) are type, decade, topic etc required fields? if so, I will probably make them a part of the path itself, such as:
../libraries/{libraryId}/type/{typeId}/rooms/{roomId}/decades/{decadeId}/topics/{topicName}/shelves/{shelfId}/locations/{shelfLocation}/books
Here I am assuming that each library can have rooms which have unique room ids per library, each room can have shelves which has unique ids/locations per room (and so on and so forth). Yes, the url is pretty long, but that's kind of expected
2) if these fields are not required, you could use a different approach which is a bit less verbose but a bit more confusing for client developers who have never used such approach here. Here's a straight up example Restful Java with JAX-RS by Bill Burke
#Path("{first}-{last}")
#GET
#Produces("application/xml")
public StreamingOutput getCustomer(#PathParam("first") String firstName,
#PathParam("last") String lastName) {
...
}
Here, we have the URI path parameters {first} and {last}. If our HTTP request is
GET /customers/bill-burke, bill will be injected into the firstName parameter and
burke will be injected into the lastName parameter.
If we follow this somewhat academic approach (I have not seen this implemented on many platforms. Most platforms normally go with approach # 1, a more verbose but clear approach), your URL would look somewhat like this:
../libraries/{libraryId}-{typeId}/rooms/{roomId}-{decadeId}-{topicName}/shelves/{shelfId}-{shelfLocation}/books
This way, if the client developer doesn't pass in the non-required fields, you can handle it at the business logic level and assign these variables a default value, for example:
../libraries/3-/rooms/2-1-horror/shelves/1-/books
With this url, libraryId = 3, typeId = null (thus can be defaulted to it's default value) and so on and so forth. Remember that if libraryId is required field, then you might want to actually make it a part of the pathparam itself
Hope this helps!

How to decide a resource in a restful way based on some tables

I need to know how to decide what is a resource and what is a sub resource. I just have some tables for which i need to make uri's. so lets say i have a student table and studentclass(which gives the name and probably some more details of the class that the student is enrolled in) table with (N:1).
I will make student a main resource and design uri like below
http://home/someapi/v1/student/1/
Following a rest approach for building uri
Qus 1: Which uri shown below do i have to make for accessing the studentclass
1.http://home/someapi/v1/studentclass?studentid=1 or
2.http://home/someapi/v1/student/1/studentclass
Do i have to consider studentclass as a separate resource..?
and
Qus 2: Suppose there is N:N relation between tables then how should the design of uri be?
I suggest to deal with two resources: student and class.
You can get a student using the following URI:
http://home/someapi/v1/students/1
Note the plural here, read this article if you want to learn why you should use plural: http://blog.apigee.com/detail/restful_api_design_plural_nouns_and_concrete_names/.
If a student can be enrolled in one class, it could be a property of this student, so you could return the following JSON document (for example):
{
"student": {
"id": 1,
"firstName": "John",
"lastName": "Doe",
"class": {
"id": 10,
"name": "Room Y"
}
}
}
You could get a specific class with the following URI:
http://home/someapi/v1/classes/10
You could get all students for a given class with this URI:
http://home/someapi/v1/classes/10/students
Now, if you have a N-N relation between students and classes, it would change my first proposal about the student representation in JSON. Actually, the class relation would become a collection of class resources, not an embedded property of a student, and you should use the following URI:
http://home/someapi/v1/students/1/classes
Meaning "retrieve all classes for student #1".
You can expose both class and student resources. No need to decide which one is the main one as they describe two different things. Having /students and /classes allows you to create students and classes, you can link them, etc.
Last thing, it's recommended to use query parameters (?foo=bar) for filtering purpose.
I think StudentClass (or simply 'Class') should be a different resource as Class can be shared amoung students. So this Uri would suit your need:
http:home/someapi/v1/studentclass?studentid=1

How to get deeply nested errors to get to my REST API?

First, some background:
I have a Company model, a Project model and a Task model. A Project belongs to a company and a Task belongs_to a Project.
The Project model holds several attributes: company_id, date. These attributes uniquely identify a project
I am letting the users create a task by API by POSTing to a URL that contains the details necessary to identify the Project. For example:
POST /projects/<comnpany_name>/<date>/tasks/
In order to make life easier for the users, in case there is no project with the given details, I'd like to create the project on the fly by the given details, and then to create the task and assign it to the project.
...And my problem is:
When there is a problem to create the project, let's say that the company name is not valid, what is the right way to return the error message and communicate to the user?
I'll explain what I mean: I added a create_by_name_and_company_name method to the Project:
def self.create_by_name_and_company_name(name, company_name)
if company = Company.find_by_name(company_name)
project = Project.create(company_id: company.id,
name: name)
else # cannot create this project, trying to communicate the error
project = Project.new(name: name)
project.errors.add(:company, 'must have a valid name')
end
company
end
I was hoping that by returning an unsaved Company object, with errors set, will be a good way communicate the error (This is similar to how rails work when there's a validation error).
The problem is that when calling valid? on the company object, it removed the error I wrote there and adds the regular validation errors (in this case, company can't be blank).
And a bonus question...
And there is a conceptual problem as well: since I'm creating a model by providing parameters that are being used to create the actual attributes, they doesn't always map nicely to the errors[:attr] hash. In this case it is not so bad and I'm using the company field for the company name parameter, but I guess this can get messier when the parameters provided to the create method are less similar to the model attributes.
So what is the preferred approach to tackle that problem? Is there something basically wrong with that approach? if so, what is the preferred approach?
About overriding the default rails validation error message, you need to write your validation constraint like this:
validates_presence_of :name, :message => "must be a valid name"
I figure that it is best to avoid such nesting and stick to a shallower API.