Skip to content
This repository has been archived by the owner on Dec 13, 2022. It is now read-only.
/ grest Public archive

Build REST APIs with Neo4j and Flask, as quickly as possible!

License

Notifications You must be signed in to change notification settings

mostafa/grest

Repository files navigation

Build REST APIs with Neo4j and Flask, as quickly as possible!

PyPI version GitHub license GitHub Actions Status Coverage Status Join the chat at https://gitter.im/pygrest/Lobby FOSSA Status Known Vulnerabilities Updates Downloads Downloads Downloads

gREST (Graph-based REST API Framework) is a RESTful API development framework on top of Python, Flask, Neo4j and Neomodel. Its primary purpose is to ease development of RESTful APIs with little effort and minimum amount of code.

⚠️ WARNING ⚠️

This package is not maintained regularly and there might be many issues, which is due to the constraints on my time and interest to contribute to its development. The original idea was to devise a simple way to store and traverse graph-based data and to create REST APIs on top of Flask and Neo4j. Today, there are many standard industry-proven technologies such as GraphQL that can do the job much better than gREST. Still, I'd be happy to help you if you have issues.

Python Version Compatibility

If you want to use gREST with Python 2.7, you will need to stick with the good old 1.4.0 version. For Python 3.x onwards, use the latest version starting with 2.x.x or the master branch.

Who's Using gREST?

If you're using gREST on your project, please let me know on Twitter or open an issue.

Features

  • Supported HTTP verbs: GET, POST, PUT, PATCH, DELETE
  • Supported response serialization methods (based on accept header): JSON, XML, YAML
  • Indexing with skip/limit and order support
  • Helper functions for handling of nodes and relations
  • Simple configuration management
  • Automatic validation of input data (plus monkey-patching of manual validation rules)
  • Deep relationship support between nodes: /primary_model/primary_model_item/related_model/related_model_item
  • Support for getting/posting relationship data between nodes
  • Support for user-defined authentication and authorization
  • Support for unicode routes (e.g. unicode tags)

Installation

To install gREST, you can use setuptools (install from source) or use a python package manager (e.g. pip or easy_install).

  • To install from source code, clone the repository (you should have git installed) and then run setup.py:
$ git clone https://github.com/mostafa/grest.git
$ cd grest
$ python setup.py install
  • To install using a python package manager via binary package, simply run this command (in this case we've used pip, but any package manager is accepted as long as it uses PyPI):
$ pip install pygrest

Edit mode installation

$ cd path/to/project
$ pip install -e .

Documentation

For detailed documentation, please visit http://grest.readthedocs.io/.

Examples

You can find an example app in examples directory.

  • app.py is a simple grest app that contains only one route (/persons).
  • extended_app.py is the extended version of the above app and contains another route (/pets), its relationship with Person model and a custom method (route) to handle RelationshipFrom properties. The RelationshipTo is automatically constructed using secondary model and secondary selection field of the PersonsView.

grest Command

The package ships a very simple command that can help you create a boilerplate Flask application. Simply run the following command:

grest <project_name>

Usage

In order to build an API, you should make a simple Flask app (or you may already have one).

A simple Flask app:

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

if __name__ == "__main__":
    app.run(debug=True, threaded=True)

To use gREST, you should define your models with Neomodel syntax. Neomodel is easier to use than other ORMs and drivers. Take a look at this example:

from neomodel import (StructuredNode, UniqueIdProperty, StringProperty)
from grest import models

class Person(StructuredNode, models.Node):
    uid = UniqueIdProperty()
    first_name = StringProperty()
    last_name = StringProperty()

As you can see, we have imported models from grest, so that we can use the Node mixin (which is used in JSON serialization of model data). Also note that the Person class (model) is inheriting from two parents: StructuredNode and Node.

Then we should inherit from grest to make a new view of our model (so that it accepts RESTful verbs):

from grest import GRest

class PersonsView(GRest):
    __model__ = {"primary": Person}
    __selection_field__ = {"primary": "uid"}

The most important part of grest is __model__ and __selection_field__ properties. They contain the logic to access your models and relations. As you see, our primary model is Person and its primary key (so to say) is uid, so the selection field of the primary model is uid.

You should register this view:

PersonsView.register(app, route_base="/persons", trailing_slash=False)

User input should never be trusted, so input validation is done by using webargs: To include input validation in each model, you should include __validation_rules__ property, which is a mapping dictionary of keys (models' fields) and values (data type and validation rules).

__validation_rules__ property is there for customization of validation rules, with the release of version 0.2.1, validation rules are inferred and constructred from your models' properties, so it is unnecessary to define it in most cases.

from neomodel import (StructuredNode, UniqueIdProperty, StringProperty)
from grest import models
from webargs import fields

class Person(StructuredNode, models.Node):
    __validation_rules__ = {
        "uid": fields.Str(),
        "first_name": fields.Str(),
        "last_name": fields.Str()
    }

    uid = UniqueIdProperty()
    first_name = StringProperty()
    last_name = StringProperty()

You can override default behavior of HTTP verbs (index, get, post, put, patch and delete) and also make custom endpoints under this PersonsView class.

Last but not least, you should set up your app's connection to the database (Neo4j), which is done by setting the DATABASE_URL propery of neomodel.config:

neomodel.config.DATABASE_URL = "bolt://neo4j:neo4j@localhost:7687"

One last part is to connect the logger of grest to Flask, or use a custom logger:

app.ext_logger = app.logger

app.ext_logger is the variable grest looks for, to log messages.

Deployment

You can run this app either in development or production environments:

As it is the same flask application, you can run it in development like this:

$ python app.py

For production purposes, you can use docker using tiangolo/uwsgi-nginx-flask:python2.7 image or use your own setup.

Contribution

Contribution is always welcome! To report bugs, simply open an issue and fill it with related information. To fix a bug, fork the repository, fix the bug, push to your own fork, make a pull request and done!

License

GPLv3

FOSSA Status