Coder Social home page Coder Social logo

Comments (3)

gi0baro avatar gi0baro commented on August 23, 2024

@arunksoman I'll try to answer your questions in the quickest way, but I surely have to start explaining the design pattern behind the REST extension.

This extension is designed to be used with the whole Emmett stack, including its ORM. The rationale was to design an immediate way to expose standard REST endpoints above a single entity, represented by a Model. The presentation layer is designed to be handled via serializers and parsers, rather than adding abstraction layers on the entity side. This also because in Emmett models can be used for a lot of things, not just exposing JSON APIs.

Given the upper foreword, I gonna split your questions in 2 groups, as one has a very simple answer, the other 2 implies quite a lot of missing context.

if the json data is not associated with any Model, how can I use this extension?

I think the most robust answer I gan give you is: probably you shouldn't use this extension for that. Plain Emmett would be definitely supportive in working with json data regardless of the source, as you have the @service.json decorator and the ServicePipe pipe to mount in your routes.

why it is mandatory to have return data from an endpoint only associated with a Model?

Because Emmett-REST is designed for RESTFul APIs, which means not just fetching json data, but works with entities: creating, updating and deleting them. And the easiest way to design a RESTFul API is having verbs for a single entity, and thus a single Model. Making changes to other entities can still be done, but it is really dependant on your application logic, and providing a common way of doing so would be impossible. Should that be done on the Model level? On the controller level? Somewhere else?

In case you want to present aggregated data coming from multiple entities, then, again, is probably easier to just write a specific get route where you produce the query and the serialization you need.

How can we create nested json schema with emmett_rest? For example, data from more than one model or data from more than one related Model?

I would say it is really dependant on the type of relation you have between your entities, and what you need to do.

For instance, is it a belongs_to? Then probably you just want to serialize and deserialize the representation of the related entity, but still work with relations in the module. Which means you probably want to write a custom serializer and a custom parser for that (you can see in the example there's the serialization of a related set of tags).

Also, since serializers and parsers are classes that can be initialized just passing the model they work on, you can define any number of serializers/parser and re-use them inside your code:

from emmett_rest import Serializer, serialize

class AssigneeSerializer(Serializer):
    attributes = ['id', 'email']

class TaskSerializer(Serializer):
    _assignee_serializer = AssigneeSerializer(User)

    def assignee(self, row):
        return serialize([row.assignee], self._assignee_serializer)[0]

For has_many relations and further, things get a bit more complicated. For sure my tendency would be to created nested REST modules rather than handling all the relations within a single one, so let's say if we have a Task and many assignees, I would prefer having a REST module working on the join model under /tasks/{task_id}/assignees instead of making a lot of logic in the Task module. Something like:

tasks = app.rest_module(__name__, 'api_task', Task, url_prefix='tasks')

class TaskRelatedPipe(Pipe):
    async def pipe(self, next_pipe, **kwargs):
        request.task = Task.get(kwargs.pop('task_id'))
        if not request.task:
            response.status = 404
            return tasks.error_404()
        return await next_pipe(**kwargs)

tasks_related = app.module(__name__, 'api_task_related', url_prefix='tasks/<int:task_id>')
tasks_related.pipeline = [TaskRelatedPipe()]

tasks_assignees = task_related.rest_module(__name__, 'api_task_asignee', User, url_prefix='assignees')

@tasks_assignees.get_dbset
def fetch_assignees():
    return request.tasks.assignees

you then probably want to remove the update method and override the create and delete ones to actually work on relations and not users, but you probably got the idea.

Managing relations inside the Task module would instead require to probably override all the methods to perform the additional operations on the related entities, which can be done as well with decorators or subclassing the basic RESTModule class, but for sure is more error-prone.

In the end, without additional context, and a clear idea on what you need to do, is quite hard to give you the "perfect answer", but I hope to have exposed all the options on the table here :)

from rest.

arunksoman avatar arunksoman commented on August 23, 2024

Thank you so much for your time. I think I have to read few more times in order understand answer. Can I ask another question? Can we still generate open API docs if we are using @service.json with the help of this extension?

from rest.

gi0baro avatar gi0baro commented on August 23, 2024

Can we still generate open API docs if we are using @service.json with the help of this extension?

Unfortunately not. OpenAPI integration is part of the REST extensions, as it uses models to generate schemas.
It is possible to add custom endpoints to OpenAPI schemas for an existing module, but not for generic routes. That will require to write all the schemas manually, and thus it felt a little pointless to give "an integration".

from rest.

Related Issues (17)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.