├── heroku_service
├── Procfile
├── config.ru
├── Gemfile
├── app.rb
├── app.json
└── Gemfile.lock
├── webhooks.db
├── webhooks_skeleton.py
├── README.md
├── webhooks_skeleton.js
├── gendb.py
├── insert_rows.py
├── package.json
└── .gitignore
/heroku_service/Procfile:
--------------------------------------------------------------------------------
1 | web: bundle exec rackup config.ru -p $PORT
2 |
--------------------------------------------------------------------------------
/webhooks.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nylas/webhooks-project/master/webhooks.db
--------------------------------------------------------------------------------
/heroku_service/config.ru:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'bundler'
3 |
4 | Bundler.require
5 |
6 | require './app.rb'
7 | run Sinatra::Application
--------------------------------------------------------------------------------
/heroku_service/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gem 'sinatra'
4 |
5 | group :development do
6 | gem 'foreman'
7 | gem 'heroku'
8 | end
9 |
--------------------------------------------------------------------------------
/webhooks_skeleton.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 |
3 | conn = sqlite3.connect('webhooks.db')
4 | c = conn.cursor()
5 |
6 | c.execute('SELECT * FROM transactions;')
7 | print c.fetchone()
8 | conn.close()
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Nylas webhooks interview problem
2 |
3 | The goal of this interview is to build a very basic webhook system to POST JSON to https://nylas-webhooks-project.herokuapp.com/webhook.
4 |
5 | To do that, we'll need to extend the code in `webhooks_skeleton.py`.
6 |
--------------------------------------------------------------------------------
/webhooks_skeleton.js:
--------------------------------------------------------------------------------
1 | const sqlite3 = require('sqlite3')
2 |
3 | let db = new sqlite3.Database('webhooks.db');
4 | let sqlQuery = 'SELECT * FROM transactions';
5 |
6 | db.all(sqlQuery, [], (err, rows) => {
7 | console.log(rows[0]);
8 | });
9 |
10 | db.close();
11 |
--------------------------------------------------------------------------------
/gendb.py:
--------------------------------------------------------------------------------
1 | import sqlite3
2 |
3 | conn = sqlite3.connect('webhooks.db')
4 | c = conn.cursor()
5 | c.execute("""CREATE TABLE transactions (id INTEGER PRIMARY KEY AUTOINCREMENT,
6 | public_id VARCHAR(64), type VARCHAR(32), record_id INTEGER);""")
7 |
8 | conn.commit()
9 | conn.close()
10 |
--------------------------------------------------------------------------------
/heroku_service/app.rb:
--------------------------------------------------------------------------------
1 | get '/' do
2 | "Nylas webhooks interview question
3 |
If you're seeing this, things have been installed correctly."
4 | end
5 |
6 |
7 | post '/webhook' do
8 | if rand(0..1) == 1 then
9 | [200, "Webhook processed!"]
10 | else
11 | [500, "Internal server error."]
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/insert_rows.py:
--------------------------------------------------------------------------------
1 | import uuid
2 | import random
3 | import sqlite3
4 |
5 | conn = sqlite3.connect('webhooks.db')
6 | c = conn.cursor()
7 |
8 | inserts = []
9 | for i in range(100):
10 | public_id = str(uuid.uuid1())
11 | type = random.choice(['create', 'update', 'delete'])
12 | record_id = random.randrange(1, 100000)
13 | inserts.append([public_id, type, record_id])
14 |
15 | print inserts
16 | c.executemany('''INSERT INTO transactions (public_id, type, record_id) VALUES (?, ?, ?)''', inserts);
17 |
18 | conn.commit()
19 | conn.close()
20 |
--------------------------------------------------------------------------------
/heroku_service/app.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sinatra-heroku-cedar-template",
3 | "description": "Sinatra Heroku Cedar Template - The bare minimum for a sinatra app on cedar, running thin, and using bundler.",
4 | "keywords": [
5 | "sinatra",
6 | "heroku",
7 | "cedar",
8 | "template"
9 | ],
10 | "website": "https://github.com/scottmotte/sinatra-heroku-cedar-template",
11 | "repository": "https://github.com/scottmotte/sinatra-heroku-cedar-template",
12 | "logo": "https://raw.githubusercontent.com/scottmotte/sinatra-heroku-cedar-template/master/sinatra-heroku-cedar-template.jpg"
13 | }
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webhooks-project",
3 | "version": "1.0.0",
4 | "description": "Nylas webhooks interview problem",
5 | "main": "webhooks_skeleton.js",
6 | "dependencies": {
7 | "sqlite3": "^4.0.2"
8 | },
9 | "devDependencies": {},
10 | "scripts": {
11 | "test": "echo \"Error: no test specified\" && exit 1"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+https://github.com/nylas/webhooks-project.git"
16 | },
17 | "author": "",
18 | "license": "ISC",
19 | "bugs": {
20 | "url": "https://github.com/nylas/webhooks-project/issues"
21 | },
22 | "homepage": "https://github.com/nylas/webhooks-project#readme"
23 | }
24 |
--------------------------------------------------------------------------------
/heroku_service/Gemfile.lock:
--------------------------------------------------------------------------------
1 | GEM
2 | remote: https://rubygems.org/
3 | specs:
4 | addressable (2.2.6)
5 | foreman (0.24.0)
6 | term-ansicolor (~> 1.0.5)
7 | thor (>= 0.13.6)
8 | heroku (2.17.0)
9 | launchy (>= 0.3.2)
10 | rest-client (~> 1.6.1)
11 | rubyzip
12 | term-ansicolor (~> 1.0.5)
13 | launchy (2.0.5)
14 | addressable (~> 2.2.6)
15 | mime-types (1.17.2)
16 | rack (1.4.0)
17 | rack-protection (1.2.0)
18 | rack
19 | rest-client (1.6.7)
20 | mime-types (>= 1.16)
21 | rubyzip (0.9.4)
22 | sinatra (1.3.2)
23 | rack (~> 1.3, >= 1.3.6)
24 | rack-protection (~> 1.2)
25 | tilt (~> 1.3, >= 1.3.3)
26 | term-ansicolor (1.0.7)
27 | thor (0.14.6)
28 | tilt (1.3.3)
29 |
30 | PLATFORMS
31 | ruby
32 |
33 | DEPENDENCIES
34 | foreman
35 | heroku
36 | sinatra
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | env/
12 | build/
13 | develop-eggs/
14 | dist/
15 | downloads/
16 | eggs/
17 | .eggs/
18 | lib/
19 | lib64/
20 | parts/
21 | sdist/
22 | var/
23 | wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | .hypothesis/
48 |
49 | # Translations
50 | *.mo
51 | *.pot
52 |
53 | # Django stuff:
54 | *.log
55 | local_settings.py
56 |
57 | # Flask stuff:
58 | instance/
59 | .webassets-cache
60 |
61 | # Scrapy stuff:
62 | .scrapy
63 |
64 | # Sphinx documentation
65 | docs/_build/
66 |
67 | # PyBuilder
68 | target/
69 |
70 | # Jupyter Notebook
71 | .ipynb_checkpoints
72 |
73 | # pyenv
74 | .python-version
75 |
76 | # celery beat schedule file
77 | celerybeat-schedule
78 |
79 | # SageMath parsed files
80 | *.sage.py
81 |
82 | # dotenv
83 | .env
84 |
85 | # virtualenv
86 | .venv
87 | venv/
88 | ENV/
89 |
90 | # Spyder project settings
91 | .spyderproject
92 | .spyproject
93 |
94 | # Rope project settings
95 | .ropeproject
96 |
97 | # mkdocs documentation
98 | /site
99 |
100 | # mypy
101 | .mypy_cache/
102 |
103 | *.swp
104 |
--------------------------------------------------------------------------------