Cloud9 & Deform

Recently I was asked about cloud9. The question was about using Flask and deform in a cloud9 environment.

This article is an answer. It contains:

Register deform project

Install CLI to signup and create your project.

If you have a project already - skip to next section

Signup

Use this command:

$ deform signup -e [email protected] -p mypassword

Deform will send you a message with confirmation code needed to confirm your email.

Confirm

To confirm your email execute this command:

$ deform confirm CODE
Register a project

To register new project use this:

deform project create -d '{"_id": "mysquare", "name": "My square"}'  

If you have some conflict errors just set the project's id as mysquare1, mysquare2 and etc.

Prepare deform credentials

Here we must prepare a token to being used in a cloud9 environment

Select a project
deform use-project mysquare9000  

This will select a project. Now we can proceed.

Create a token

We must create a token which will be able to:

  • create and read a documents in a collection named venues

This token won't be able to delete your venues. It also won't be able to operate with other collections and theirs documents.

$ deform document create -c _tokens -d '{
  "_id":"create_read_venues_token",
  "name": "Read and create Venues",
  "is_active": true,
  "permission": {
    "allow": {
      "read": [
        {
          "what": "document",
          "where": "venues"
        }
      ],
      "create": [
        {
          "what": "document",
          "where": "venues"
        }
      ]
    }
  }
}'

Nice, now we have a token with unique identifier create_read_venues_token

Create a collection

Because this token cannot operate with collections - let's create a collection using CLI

deform collection create -d '{"_id":"venues", "name":"venues"}'  

Now we must prepare cloud9 env.

Prepare cloud9 environment
Create new workspace

You should select a Python workspace.

Install dependencies

We will use flask and python-deform

sudo pip install flask python-deform  

You can also install dependencies into virtualenv.

Some code

Most interesting part is coding part.

/bin/app.py

import os  
import tempfile

from flask import Flask, jsonify, request  
from pydeform import Client

app = Flask(__name__)

# Init deform client
client = Client(host='deform.io')

# Auth with a token
token_client = client.auth(  
    'token',
    auth_key='create_read_venues_token',
    project_id='mysquare9000',
)


@app.route("/venues/", methods=["GET"])
def venues_list():  
    page = request.args.get('page', 1)
    per_page = request.args.get('per_page', 100)

    response = token_client.documents.find(
        collection="venues",
        page=page,
        per_page=per_page,
    )
    return jsonify(response)


@app.route("/venues/", methods=["POST"])
def venue_create():  
    if request.headers.get("Content-Type") == "application/json":
        data = request.get_json()

        if len(data) > 0:
            response = token_client.document.create(
                collection="venues",
                data=data
            )
            return jsonify(response)
        else:
            response = jsonify({'message': 'need valid json'})
            response.status_code = 400
            return response
    else:
        file = request.files["image"]
        data = {
            "_id": request.values.get("_id"),
            "name": request.values.get("name"),
        }

        fp = tempfile.TemporaryFile()

        if len(file.mimetype) > 0:    
            fp.write(file.read())
            fp.seek(0)

            data.update({
                "image": fp
            })
        try:
            response = token_client.document.create(
                collection="venues",
                data=data,
            )
            return jsonify(response)
        finally:
            fp.close()


@app.route("/venues/<venue_id>/", methods=["GET"])
def venue_detail(venue_id):  
    response = token_client.document.get(
        collection="venues",
        identity=venue_id,
    )
    return jsonify(response)


host = os.getenv('IP', '0.0.0.0')  
port = int(os.getenv('PORT', 8080))  
app.run(  
    host=host,
    port=port,
    debug=True
)

Please note:

  • venue_create function can only create once, otherwise you will encounter HTTP 409 - Conflict error.
CURL It

Now it's about time to try commit some HTTP Requests.

I will use Curl.

Create a venue

$ curl -X POST -F "_id=kfc2" -F "name=KFC" -F "rating=5" -F "image=@/tmp/cover.jpg" https://reddit-flask-deform-firewut.c9users.io/venues/
{
  "_id": "kfc2", 
  "image": {
    "_id": "577be6f294d5de0005506201", 
    "collection_id": "venues", 
    "content_type": "image/jpeg", 
    "date_created": "2016-07-05T16:57:22.825866225Z", 
    "document_id": "kfc2", 
    "last_access": "2016-07-05T16:57:22.825866225Z", 
    "md5": "a8eda376612338e0286ff1c1a725b111", 
    "name": "image", 
    "size": 16214
  }, 
  "name": "KFC"
}

Select all venues

$ curl -X GET https://reddit-flask-deform-firewut.c9users.io/venues/
{
  "items": [
    {
      "_id": "kfc2", 
      "image": {
        "_id": "577be6f294d5de0005506201", 
        "collection_id": "venues", 
        "content_type": "image/jpeg", 
        "date_created": "2016-07-05T16:57:22.825866225Z", 
        "document_id": "kfc2", 
        "last_access": "2016-07-05T16:57:22.825866225Z", 
        "md5": "a8eda376612338e0286ff1c1a725b111", 
        "name": "image", 
        "size": 16214
      }, 
      "name": "KFC"
    }, 
    {
      "_id": "kfc", 
      "image": {
        "_id": "577be62194d5de00055061fe", 
        "collection_id": "venues", 
        "content_type": "image/jpeg", 
        "date_created": "2016-07-05T16:53:53.286733926Z", 
        "document_id": "kfc", 
        "last_access": "2016-07-05T16:53:53.286733926Z", 
        "md5": "a8eda376612338e0286ff1c1a725b111", 
        "name": "image", 
        "size": 16214
      }, 
      "name": "KFC"
    }
  ], 
  "page": 1, 
  "pages": 1, 
  "per_page": 100, 
  "total": 2
}

Select single venue

$ curl -X GET https://reddit-flask-deform-firewut.c9users.io/venues/kfc2/
{
  "_id": "kfc2", 
  "image": {
    "_id": "577be6f294d5de0005506201", 
    "collection_id": "venues", 
    "content_type": "image/jpeg", 
    "date_created": "2016-07-05T16:57:22.825866225Z", 
    "document_id": "kfc2", 
    "last_access": "2016-07-05T16:57:22.825866225Z", 
    "md5": "a8eda376612338e0286ff1c1a725b111", 
    "name": "image", 
    "size": 16214
  }, 
  "name": "KFC"
}

That's all. If you still have a questions feel free to ask in a comments section or any contact available.