S
S
Sergey2018-04-13 23:14:43
MongoDB
Sergey, 2018-04-13 23:14:43

How to design a RESTful API?

There is the following data structure:
Mongo models: User, Course, Lesson
User roles: admin, teacher, student
Relationships will be like this:

User: {
    name: 'Teacher',
    role: 'teacher',
    courses: [{
        title: 'Course',
        lessons: [{
            title: 'Lesson'
        }]
    }]
}

teacher - can CRUD his courses and lessons
admin - can CRUD anything
student - can READ any lessons, ideally only those to which he has access
To distribute access rights, I want to use ABAC access control
Example:
admin { courses: ' read:any' } - can read any courses
teacher { courses: 'read:own' } - can only read own courses
student - { courses: 'read:any' } - can read any courses
Question 1. How to grant access to a user to a specific lesson in ABAC style?
Briefly about CRUD
POST -     Create
GET -       Read
PUT -       Update
DELETE - Delete

How I see the organization of the architecture:
CRUD for /users - everything seems to be clear here
GET, POST /users
PUT, GET, DELETE /users/:uuid

Nothing complicated ;)
Now let's look at creating user resources:
PS We use passport and we always have the current user in req.user
CREATE for courses
First approach:
request:
POST users/:userUuid/courses - req.body { title } // создаем курс у пользователя

handler:
userUuid === req.user.uuid // проверяем права доступа
course = Course.create({ title })
user = User.find({ uuid: userUuid })
user.courses.push(course._id).save()

To get the user's courses, we will do this:
request:
GET /courses/:courseUuid
handler:
course = Course.findOne({ uuid: courseUuid })
user = User.findOne({ 'courses': course._id})
user.uuid === req.user.uuid // проверяем права доступа, если true возвращаем курс

but it's some weird restful,
POST user/:userUuid/course
но
GET /course/:courseUuid

Next, create a lesson:
request:
POST /courses/:courseUuid/lessons
handler:
course = Course.findOne({ uuid: courseUuid })
user = User.findOne({ courses: course._id})
user.uuid === req.user.uuid // проверяем права доступа, если true - можно создавать урок

lesson = Lesson.create({ title })
course.lessons.push(lesson._id)

And reading
request:
GET /lesson/:lessonUuid
handler:
lesson = Lesson.findOne({ uuid: lessonUuid })
course = Course.findOne({ lessons: lesson._id })
user = User.findOne({ courses: course._id})
user.uuid === req.user.uuid // проверяем права доступа, если true - можно вернуть урок

And if we want to add some quiz to the lesson, then this will again be a chain of owner pre-checks.
Somehow everything is not optimal and it doesn’t look like RESTful, please advise how it is usually organized in general?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
D
Dmitry Entelis, 2018-04-14
@DmitriyEntelis


Somehow everything is not optimal and it doesn’t look like RESTful, please advise how it is usually organized in general?
Suggestion: RESTful looks good only in tightly synthetic examples of an abstract object catalog without business logic and relationships.
but it's some weird restful,
POST user/:userUuid/course

Why not POST /course/? Your course is an independent object, it is not a property of the user.

⚡ Kotobotov ⚡, 2018-04-14
@angrySCV

user data is passed either as a parameter in the link, or as a request header , so you can GET
, POST /course/ :
courseUuid /:lessonUuid common approach to have a unified api, with the same POST and GET (and additional low hierarchy requests like /lesson/:lessonUuid)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question