0

I was recently considering the difference between using raw SQL and using a query builder like knex.js for writing dynamic queries so that I get any level of granularity for filtering database tables.

Is it bad practice to allow for any level of granularity for user input in a REST API as long as I consider the implications of allowing this, and build in dynamic permissions for user roles? Is there a better way to do this?

An example would be some endpoint let's say /book where it has several database fields and the frontend may want to search by any subset of the fields and if the underlying data changes the API will dynamically use the fields passed in as search parameters if they exist.

And for editing/creating is it bad practice to use the same level of granularity provided that the user permissions are considered for editing resources?

My reasoning for this design is so that the application can have several different frontends and each frontend may use resources in different ways. This seems like it would simplify all of these use cases to one REST endpoint.

I've never received an answer as to how to create useful REST APIs that can be utilized efficently by thick clients with high granularity and all examples that I've seen seem to hard-code field names into backend services. Would it make more sense to have a factory for creating granular CRUD endpoints for simple objects and only more complicated endpoints need to have hard-coded logic for processing.

Ex as an express.js middleware:

bookController.get = async (req, res, next) => {
    //assume this was validated in another middleware but came from the req.query object
    //could contain any subset of db fields
    const query = res.locals.query;
    try{
        const books = await getBooks(query);
        res.json(books);
    }
    catch(e) {
        next(e);
    }
}

//assuming that the db functions would dynamically create a sql query then execute it
async function getBooks(query) {
    return await db.query('books').select('*').where(query);
}
  • Over-engineering a design is one of the big invisible costs in a project. If you will never have any other useful work you could be doing, then spend all the time and energy you want providing finer and finer control. In the real world, we try to find out what the client needs and deliver that. – BobDalgleish Oct 25 '19 at 21:26
  • Is this really over-engineering? If anything it seems like under-engineering. It offers the most granularity on resources possible on the backend and pushes the development work for specifics to the frontend, there is almost nothing in the way of data processing (other than verification and permission checking) on the backend. It would be more work for me to give less control because all of the application specific are left to the frontend developer and this is a simple dynamic endpoint for each resource with a high level of code reuse for each resource. – Alex Oct 25 '19 at 21:46
  • Can you explain why you would want to do this? Are you anticipating that your DB schema will be changing all the time? It sounds like you don't want REST at all here but rather you want to give your clients direct access to your DB and let the client just run SQL queries on your DB. This is very much not how REST works, but you don't have to use REST if it doesn't suit your use case – Cormac Mulhall Oct 29 '19 at 15:25
  • This question was more of a hypothetical, the motivation for it is: the frustration that comes with changing requirements often means large rewrites to the backend. The simplicity of allowing for a high level of granularity means it doesn't need large changes on the backend, only the frontend needs rewrites. The database schema changing is more of a side benefit and not my main motivation. The design I was considering for this question would have some dynamic permissions that would restrict the granularity of requests with a RBAC model. – Alex Oct 29 '19 at 17:10
  • I guess this is basically asking why not have a very database like backend. Perhaps I've been designing my api's with the wrong priorities. I always try to write the thinnest backend possible so the I can leave as much as possible to the frontend. – Alex Oct 29 '19 at 17:13
2

The REST interface is designed to be efficient for large-grain hypermedia data transfer, optimizing for the common case of the Web, but resulting in an interface that is not optimal for other forms of architectural interaction. -- Fielding, 2000

(emphasis added).

Caching is a key pillar in the REST architectural style; that's more consistent with the approach where you fetch a data transfer object, and then on the client extract from it the data that you need.

On the web, the "application state" is often a composition of an HTML representation that includes links to other resources (scripts, images, movies); what that allows you to do is control each with an appropriate caching policy, and allows you to efficiently re-use some resources in other states.

it would simplify all of these use cases to one REST endpoint.

Well - yes, if you relax the constraints, you get an easier implementation. But in doing that, you also give up the properties that were guaranteed by those constraints. Welcome to the world of trade-offs.

RPC/SOAP/gRPC isn't wrong, but they are tools designed to fit a different problem than the REST constraints. If you don't have the problems that REST is designed to solve, then tunneling messages may be fine.

|improve this answer|||||
0

Any answer will be based on personal opinion (rather than facts); I'll give mine.

I think it's not a good idea to build as much granularity as possible into a REST API, but there are cases where high granularity is useful and valid.

Your book example is great. Books often have a lot of metadata and clients should be able to search for books on any combination of metadata values. This is widely used in the HTTP world. Go to a library's website - it will have a form where you can enter a combination of metadata values to search for a book. HTTP query parameters are especially designed for this purpose.

But don't just offer unconstrained access to your database. Put a server-side business layer in between. It offers the following advantages:

  1. It hides the physical structure of your database, so that you may optimize your table structure without impact on the clients.

  2. It provides a layer of abstraction that is more easy to use for the clients.

  3. It can perform checks, so that requests and updates that do not make sense from a business perspective are rejected.

For more information about my opinion on REST API design, see www.admiraalit.nl/jarest

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.