apinf / openapi-space

A backend for storing OpenAPI specifications
https://openapi.space
European Union Public License 1.1
4 stars 3 forks source link

Decide on the tools and architecture of the backend #1

Closed tulir closed 7 years ago

tulir commented 7 years ago

Before doing anything else we should decide a few things:

We'll most likely use Flask for the web server and SQLAlchemy for the database. We'll probably also want to use something like connexion or swagger-py-codegen

For the the server architecture, there are currently two main ideas:

  1. A Git-like server where saved specs are immutable, but anyone can create a new revision based on a saved spec. This approach wouldn't require implementing any authentication.
  2. An open-source implementation of the Swagger Hub spec
tulir commented 7 years ago

The Git-like approach is probably better when integrating into the APInf platform or other platforms that have their own authentication system. However, it would not be as easy to use as a standalone system.

MikeRalphson commented 7 years ago

Happy with Flask/SQLAlchemy. Connexion seems to have the edge over swagger-py-codegen (which is only an Alpha release) at least when it comes to generating runnable code from the swaggerhub API definition.

A Git-like server where saved specs are immutable, but anyone can create a new revision based on a saved spec. This approach wouldn't require implementing any authentication.

I can see a simple key/hash : value store being simpler to get up and running, but I suspect creating namespaces, aliases or some other mechanism to separate the API definitions would be almost as much work as authentication.

mauriciovieira commented 7 years ago

A Git-like server where saved specs are immutable, but anyone can create a new revision based on a saved spec. This approach wouldn't require implementing any authentication.

In this case, we might want to not handle version-control in database manually. Is there anything like the solutions for rails?

An open-source implementation of the Swagger Hub spec

I like this idea better. Since the endpoints and specs are already there, it can be a nice opportunity to do test-driven-development.

brylie commented 7 years ago

If we might be having user accounts, Django might be worth considering:

One tipping point I have heard multiple times is that if you need a login system for your users definitely consider Django over Flask.

Gnlfbz on /r/django discussion Why Django over Flask?


As soon [user accounts] become a requirement, I consider Django over Flask.

_wsgeorge on /r/django discussion Why Django over Flask?

There is also a Django extension, called Reversion, that makes it easy to store document revisions.

brylie commented 7 years ago

Another interesting comment:

I would go for DRF (though I haven't used Flash extensively), because it will include features that you may not be aware you need them until it's too late (such as multiple, pluggable authentication systems or the ease of its included serializers).

Bare-bones routing, implementation of HTTP verbs and DB lookups are the easy part (and completely do-able in vanilla Django or Flask). It's the extra bits that make an API usable and cleanly implementable that are hard and you get those with DRF.

virtron on /r/django discussion Flask vs Django Rest Framwork

brylie commented 7 years ago

This comment is somewhat relevant, although we have not discussed whether we will have a UI that needs forms:

When starting a new hobby project I always consider using Flask first unless it needs models. If I need models, there's a 98% probability that I need user management and forms too. And instead of installing flask-sqlalchemy, flask-wtf, flask-login and whatnot, I just use Django instead.

Retzudo on /r/flask discussion Django vs Flask: A practitioner’s perspective (2017)

This one is straightforward:

for database apps we use django.

scottocom on /r/flask discussion Django vs Flask: A practitioner’s perspective (2017)

brylie commented 7 years ago

I realize these are cherry-picked comments (aren't all quotes cherry picked?). In any case, the discussions are relevant to our current decision.

I am fine with either Django or Flask, but just wanted to share the Django side of things.

xylix commented 7 years ago

@brylie Before deciding on web frameworks we should probably decide which of these:

solutions we are going with, or are we planning on doing something else?

brylie commented 7 years ago

The quotes above are intended to support the discussion of user authentication, document revisioning, etc., not to force a decision about framework at this point.

For the Git-like approach, how might an OpenAPI document be identified? Would namespacing be relevant/needed?

tulir commented 7 years ago

Namespacing would probably not be needed, at least not at the beginning. We could just store a hash or other unique value as the key and somehow link other revisions to make browsing the history/future possible.

brylie commented 7 years ago

One idea would be to store a revision history within the APInf codebase, since we are planning to integrate the designer interface into the APInf UI. That would help keep the OpenAPI Space project requirements small.

Also, we agreed that document revisions, in the sense of keeping a history of revisions linked in some way, was out of scope.

xylix commented 7 years ago

@brylie You mean something like OpenAPI Space would only store the freshest versions of a spec and when the user saves a new version the old version would be sent into an apinf.io side revision database? Would this eliminate the benefit of not requiring authentication for users of OpenAPI Space?

Also I don't see the point of splitting code that stores OpenAPI specs this way? Why not just have it all in one place, OpenAPI Space? The same amount of code will be required anyway to reach the same functionality, or at least that's what I am thinking.

brylie commented 7 years ago

You mean something like OpenAPI Space would only store the freshest versions of a spec and when the user saves a new version the old version would be sent into an apinf.io side revision database?

No, just that each revision would be it's own document. Each document could have a unique identifier (e.g. hash). The OpenAPI specs are only stored in OpenAPI Space.

I only suggested that APInf could store the revision history, e.g. as an array of hashes. That way OpenAPI Space doesn't need to link the revisions.

tulir commented 7 years ago

Yeah, we could leave linking the revisions to a later version or even leave it out completely. Even with linked revisions, APInf would need to remember what revision the user is on since anyone could create a new revision.

brylie commented 7 years ago

Jep. We already agreed that revisions are out-of-scope for the current project phase. We are 'on the fence' about authentication.

Basically, I can think of a way we could handle revisions, if needed, in APInf Platform.

xylix commented 7 years ago

@brylie Thanks for the clarification. Yeah that would make sense if we want to go for the "hash solution" for stored spec identification. If so, we need to design the API.

mauriciovieira commented 7 years ago

I vote for Django Rest Framework + Django Reversion + user authentication + document versioning (for each user) + test driven development

MikeRalphson commented 7 years ago

Is it possible to do design-first development with Django REST Framework - i.e. drive/generate the API implementation from an OpenAPI/Swagger definition? Maybe m'colleague @piersstorey can comment.

brylie commented 7 years ago

Is it possible to do design-first development with Django REST Framework - i.e. drive/generate the API implementation from an OpenAPI/Swagger definition?

Good question. I will also research this idea and wait for any comment from @piersstorey.

In any case, we can design first by creating a specification file and then developing code based on that file.

brylie commented 7 years ago

After searching around, I can't find any tooling to generate a Django REST Framework API from a Swagger/OpenAPI Spec file. The question has been raised on StackOverflow in 2016, with no answer.

xylix commented 7 years ago

@brylie Here is one quite big project that does that: https://github.com/marcgibbons/django-rest-swagger

edit: That tool does the exact reverse of what we are trying to do. I read the description wrong, sorry.

brylie commented 7 years ago

@xylix I think Django REST Swagger will generate an OpenAPI/Swagger spec from server code.

code --> spec file

I think @MikeRalphson was asking about any tools that would generate server code from a specification.

spec file --> code (server stub)

See the following projects for examples of the spec --> code idea:

piersstorey commented 7 years ago

@brylie @xylix @MikeRalphson Django REST Swagger generates OpenAPI/Swagger spec from server code eg: Django model (Data ORM class) -> views.py -> Swagger spec

xylix commented 7 years ago

There doesn't seem to be any well-known ways of generating django server side code from OpenAPI specs. I like the idea of using a design first approach so I think we should go with flask.

brylie commented 7 years ago

I like the idea of using a design first approach

Lets start with an OpenAPI spec design file. That way, we can get validation for the design ideas quickly.

Later, we can decide whether generating a server stub would be useful in our development process.

tulir commented 7 years ago

I created a pull request for a basic OpenAPI spec: #6

MikeRalphson commented 7 years ago
xylix commented 7 years ago

I found a design first django tool. https://github.com/akx/lepo However it calls itself a "contract first API framework".

brylie commented 7 years ago

Lepo is Finnish for rest.

Haha, appropriate 😁

mauriciovieira commented 7 years ago

@xylix @tulir @brylie I took a look at Lepo, it just generates plain function-based views, and don't profit from the best of Django Rest Framework.

mauriciovieira commented 7 years ago

So, my vote to end this discussion is:

brylie commented 7 years ago

My 'vote' goes to Django REST Framework / Lepo.

brylie commented 7 years ago

Choose a person that will have the last word :-p (not me)

I move that @xylix should make the final decision. All in favor, please give a thumbs up on this comment.

xylix commented 7 years ago

We are planning to use django. Will confirm other details within 19 hours.

xylix commented 7 years ago

The SwaggerHub spec contains tons of definitions that are hard to understand without getting a look at their own implementations. We are going to create our own API spec based on SwaggerHub's, which will try to contain as much of the needed features as possible.

We will implement authentication using django's authentication system.

We won't use Lepo, because if we need to rewrite the code anyway it won't really help.

We won't start by writing tests but we will aim for high code coverage soon.

MikeRalphson commented 7 years ago

We won't use Lepo, because if we need to rewrite the code anyway it won't really help.

Is it worth forking Lepo to produce DRF ModelViewSets instead, and look at contributing that code back, or with a cut-down OpenAPI base, will there not be such a need for code-generation?

brylie commented 7 years ago

@akx what are some considerations and challenges regarding Lepo supporting DRF ModelViewSets?

tulir commented 7 years ago

We tried using ModelViewSets, but they seem to be a bit too abstract, since there's some work to do to convert the data being POSTed to our data models.

akx commented 7 years ago

Hey guys :)

Glad you stumbled upon Lepo – I haven't really advertised it anywhere and it's definitely in beta stage and nowhere near DRF's scope at present (nor do I think it'll ever be, really!). Disclaimers aside, then...

The reason I wrote Lepo in the first place was that @japsu was lamenting the lack of design-first API tools for Django. As noted earlier in the thread, DRF and related tools only do the reverse (and in my opinion, not that well.) So if you want something that you first write an OpenAPI spec for, then write the code, there aren't really any options for Django other than Lepo.

@mauriciovieira:

I took a look at Lepo, it just generates plain function-based views, and don't profit from the best of Django Rest Framework.

The codegen is really an afterthought/convenience tool in Lepo that gets you kickstarted/scaffolded with handlers for the various API calls described by the API.

To further explain what's going on in Lepo ––

In Django, views are callables with the signature (request, *args, **kwargs) -> Response, where the args and kwargs come from the URL router. Lepo adds a transform layer of sorts (the router and the views it generates) there; if you have an OpenAPI operation with parameters, say, name and comment, you'd instead write a handler with the signature (request, name, comment) -> Response | dict and map it through the operationId field in your OpenAPI doc. Lepo will take care of transforming the input data (be it query parameters, form data, raw POST or path fragments) into those args.

Anyway... Although it hasn't been tried, there's nothing that'd really stop you from using DRF's viewsets as the "backend" for Lepo/OpenAPI -described API calls. The glue code shouldn't be too complex, though of course you'd have to be careful to keep your DRF serializers etc. in sync with your OpenAPI document.

Oh, and for what it's worth, Lepo's (ahem, undocumented-but-tested) class-based handler API is loosely based on DRF viewsets anyway.

Hope this helps! Also, I'd be super glad to help you guys in any way if you decide to go down the Django/Lepo route!

xylix commented 7 years ago

We have been working at django-test, lepo-test and flask-test with @tulir for a couple of workdays now. We had problems using Django, partially because of our inexperience with it, so we decided that for getting this project properly going flask will work better for now. So we are now making a PR from flask-test into master which will be the implementation we are now planning to use, at least for now. It uses Flask with connexion and SQLAlchemy.

tulir commented 7 years ago

The Flask version is now working with support for all operations in the spec and has been merged into master.