
FastAPI – Easily create robust, standardized API endpoints in Rails and Postgres - keithwhor
https://github.com/thestorefront/FastAPI
======
carlosdp
I'm confused as to why view logic is being moved to the Model layer, directly
breaking MVC. Why is this better than using the tools in Rails that already
exist for every use case here? Is there a performance increase?

~~~
jerhinesmith
I came here to say the exact same thing. After having worked on/scaled an API
that served >100k requests per minute, I feel I can say with some experience
that defining your JSON in your model is a very bad idea.

A classic example that we ran into repeatedly: Assume you want to have an
endpoint that populates a user's profile (for the user to see). You probably
want id, name, email, age, location, created_at, updated_at, etc. However,
when exposing this same user instance through an endpoint that publicly
aggregates users (e.g. search), sending over all those fields is 1) overkill,
and 2) raises privacy concerns.

So far, my favorite approach to this problem uses the ActiveModel::Serializer
gem ([https://github.com/rails-
api/active_model_serializers](https://github.com/rails-
api/active_model_serializers)). It moves the JSON logic to something more akin
to a view, and provides an easy way to present instances differently depending
on the context.

~~~
Glyptodon
I don't think there's actually a good way to solve this (that I know of) for
applications with complex enough permission and role hierarchies.

Once you need a list of all the glass marbles with their attributes, but can
only see the color of marbles you supervise, and only the radius of a marble
if it has a shooter role and only the names and emails of marbles ranked above
you... ...and so on... it becomes a situation where each result has to be
filtered item by item pretty much. And the filter hierarchies will snowball
like tribbles.

~~~
lumpypua
The `djangorestframework-composed-permissions` package for DRF gets pretty
close to handling this situation effectively. Basically roles and permissions
arbitrarily composable with boolean expressions.

Although you can model permission hierarchies, I think there are enough corner
cases that it's worthwhile to declare permissions as explicitly as
conveniently possible.

API Docs: [https://djangorestframework-composed-
permissions.readthedocs...](https://djangorestframework-composed-
permissions.readthedocs.org/en/latest/)

------
joshmn
This looks cool. My (current) favorite rollout for APIs with Ruby/Rack/Rails
is Grape[0] with ASM[1].

[0] [https://github.com/intridea/grape](https://github.com/intridea/grape) [1]
[https://github.com/jrhe/grape-
active_model_serializers](https://github.com/jrhe/grape-
active_model_serializers)

------
adamonduty
I'm a little scared that this builds SQL statements directly. Did you consider
at least using prepared statements? Was there such an awful performance hit
using ActiveRecord, or something that couldn't be done with it?

~~~
keithwhor
Yep --- couldn't effectively use and parse subqueries with ActiveRecord alone.

------
samgranieri
Why was this even created? ActiveModelSerializers or Rabl works just fine

~~~
Glyptodon
The reason this project (and many others like it) exist is pretty obvious:
Lots of people have to build different kinds APIs using rails, get some
experience with Rails, discover it sucks for building APIs out of the box (to
much anti-DRY repetition, doesn't deal with auth/permission dichotomy well),
and then proceed to roll their own API layer/Auth layer/Permission layer
because either:

a) information on existing solutions is hard to find/not obvious or otherwise
in the world of unknowns to the author

or

b) existing solutions are too generalized or otherwise structured in ways that
don't work for whatever real world particular business cases.

I ran into this with permissions in my current project. Nothing _obvious_ in
my realm of knowledge fit (sometimes I suspect this happens because projects
only advertise their basic features clearly). So I now have a massive custom
permission layer.

Sometimes you also end up with things like this by accident - you need one
thing, it's not worth going whole hog to begin with, but then suddenly stuff
gets tacked on until you have a whole system you never set out to build.

------
rubiquity
Why would I use this over ActiveModel::Serializers?

~~~
keithwhor
The goal of this project is for easy model accession / querying via JavaScript
or some other external interface. The most powerful part of this
implementation, I would argue, is the filtering of endpoint data via
request.query_parameters.

This allows for "people/?age__gte=25" and other simple logic filters that can
be communicated over the HTTP request, and is standard across all models and
endpoints.

~~~
jerhinesmith
Couldn't you easily accomplish the same thing via the ransack gem?

[https://github.com/activerecord-
hackery/ransack/wiki/Basic-S...](https://github.com/activerecord-
hackery/ransack/wiki/Basic-Searching)

~~~
keithwhor
Yes, I'm sure you could --- in combination with ActiveModel::Serializer.

Our approach was meant to attack a combination of common, specific problems
(standardized way to output API data, queryable with logic via HTTP
parameters, a single SQL query to collect and aggregate data) with a dead
simple, low-overhead solution.

------
pjam
I like the idea, but I would be really reluctant to use a gem that has no
tests, especially when the core methods are clearly not trivial, a bunch of
them are ~100 lines long. Not that the number of lines tells how complicated a
method is, but I think it is a good indicator.

~~~
bradrobertson
I was going to say the same thing. I wouldn't even think about touching this
gem. Multiple methods close to 200 lines long, all in a single file with no
test suite. I shudder to think what the cyclomatic complexity of the
'api_comparison' method is. Have fun contributing to this project.

------
bg23
It's named 'Fast' API. Is it any faster then using Active Model Serializers?

------
andyl
There is grape, grape-swagger, grape-swagger rails, and a bunch of other gems
for creating API's. They work amazingly well, and have a pretty active
community. They have solved a ton of issues: Jsonp, Cors, authentication, rate
limiting, versioning, and DOCUMENTATION. The auto-generated Swagger
documentation is a real thing of beauty.

