Permalink
Browse files

First version of working example

  • Loading branch information...
1 parent 12e77e3 commit b14d1a0fd70361aa7df30be5c9d8b4234b9dc410 @djones committed May 11, 2012
Showing with 320 additions and 3 deletions.
  1. +10 −0 Gemfile
  2. +85 −0 Gemfile.lock
  3. +1 −0 Procfile
  4. +95 −3 README.md
  5. +47 −0 Rakefile
  6. +20 −0 app/api/posts_api.rb
  7. +5 −0 app/models/post.rb
  8. +22 −0 config/application.rb
  9. +9 −0 config/database.yml
  10. +11 −0 db/migrate/1_create_posts.rb
  11. +15 −0 server.rb
View
10 Gemfile
@@ -0,0 +1,10 @@
+source 'https://rubygems.org'
+
+gem 'pg'
+gem 'em-postgresql-adapter', :git => 'git://github.com/leftbee/em-postgresql-adapter.git'
+gem 'rack-fiber_pool', :require => 'rack/fiber_pool'
+gem 'em-synchrony', :git => 'git://github.com/igrigorik/em-synchrony.git',
+ :require => ['em-synchrony', 'em-synchrony/activerecord']
+
+gem 'grape'
+gem 'goliath'
View
@@ -0,0 +1,85 @@
+GIT
+ remote: git://github.com/igrigorik/em-synchrony.git
+ revision: de0efbb3c7d19df352697fa20960a5f84d082a7e
+ specs:
+ em-synchrony (1.0.1)
+ eventmachine (>= 1.0.0.beta.1)
+
+GIT
+ remote: git://github.com/leftbee/em-postgresql-adapter.git
+ revision: c9b31df6d3177ac22f94b08d6b722009ac089215
+ specs:
+ em-postgresql-adapter (0.3)
+ activerecord (>= 3.1.0)
+ eventmachine
+ pg (>= 0.8.0)
+
+GEM
+ remote: https://rubygems.org/
+ specs:
+ activemodel (3.2.3)
+ activesupport (= 3.2.3)
+ builder (~> 3.0.0)
+ activerecord (3.2.3)
+ activemodel (= 3.2.3)
+ activesupport (= 3.2.3)
+ arel (~> 3.0.2)
+ tzinfo (~> 0.3.29)
+ activesupport (3.2.3)
+ i18n (~> 0.6)
+ multi_json (~> 1.0)
+ arel (3.0.2)
+ async-rack (0.5.1)
+ rack (~> 1.1)
+ builder (3.0.0)
+ eventmachine (1.0.0.beta.4)
+ goliath (0.9.4)
+ async-rack
+ em-synchrony (>= 1.0.0)
+ eventmachine (>= 1.0.0.beta.3)
+ http_parser.rb
+ http_router (~> 0.9.0)
+ log4r
+ multi_json
+ rack (>= 1.2.2)
+ rack-contrib
+ rack-respond_to
+ grape (0.2.0)
+ hashie (~> 1.2)
+ multi_json
+ multi_xml
+ rack
+ rack-mount
+ hashie (1.2.0)
+ http_parser.rb (0.5.3)
+ http_router (0.9.7)
+ rack (>= 1.0.0)
+ url_mount (~> 0.2.1)
+ i18n (0.6.0)
+ log4r (1.1.10)
+ multi_json (1.3.4)
+ multi_xml (0.4.4)
+ pg (0.13.2)
+ rack (1.4.1)
+ rack-accept-media-types (0.9)
+ rack-contrib (1.1.0)
+ rack (>= 0.9.1)
+ rack-fiber_pool (0.9.2)
+ rack-mount (0.8.3)
+ rack (>= 1.0.0)
+ rack-respond_to (0.9.8)
+ rack-accept-media-types (>= 0.6)
+ tzinfo (0.3.33)
+ url_mount (0.2.1)
+ rack
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ em-postgresql-adapter!
+ em-synchrony!
+ goliath
+ grape
+ pg
+ rack-fiber_pool
View
@@ -0,0 +1 @@
+web: bundle exec ruby server.rb -sv -e prod -p $PORT
View
@@ -1,4 +1,96 @@
-grape-goliath-example
-=====================
+# [Grape](https://github.com/intridea/grape) + [Goliath](https://github.com/postrank-labs/goliath) Example
-A non-blocking example application of Grape and Goliath being used together with a Postgres database
+## What is this?
+
+* Grape is micro-framework for creating REST-like APIs in Ruby.
+* Goliath is a non-blocking Ruby web server
+
+Together you can create a highly scalable API and use the nice features of Grape to specify how your REST API will work.
+
+This example features:
+
+* ActiveRecord models
+* Postgres
+* Non-blocking adapters and dependancies
+* Deployment on Heroku
+
+## Getting Started
+
+Create and migrate your database with:
+
+ $> rake db:setup
+
+Start the server and you're done!
+
+ $> ruby server.rb -vs
+
+Next let's list all the posts in the database:
+
+ $> curl http://localhost:9000/v1/posts.json
+ => []
+
+There are none yet.
+
+## Adding a Post
+
+We do a HTTP post to create a new post.
+
+ $> curl -X POST -d '{"post":{"title":"David Jones","body":"this is my message"}}' http://localhost:9000/v1/posts/create
+
+Now let's list all the posts again.
+
+ $> curl http://localhost:9000/v1/posts.json
+ => [{"body":"this is my message","created_at":"2012-05-11T13:35:03-07:00","id":1,"title":"David Jones","updated_at":"2012-05-11T13:35:03-07:00"}]
+
+Now you see your first post has shown up.
+
+# Next Steps
+
+This is just a basic Grape API example. You can see the post specified in `app/api/posts_api.rb`. You could expand that API and add your own models in `app/models`.
+
+# Deploy on Heroku
+
+First we create a new Heroku application
+
+ $> heroku create --stack cedar YOURAPPNAME
+
+Next we push the code to Heroku
+
+ $> git push heroku master
+
+You'll see a URL at the end of your deploy. Use that to fill in the YOURAPPNAME in the next step.
+
+ $> curl http://YOURAPPNAME.herokuapp.com/v1/posts.json
+ => []
+
+Next you could use the "Adding a Post" example above to write your first post to the server.
+
+# Extras
+
+*Locally only*, you can use Rails-like database commands.
+
+Drop your database with:
+
+ $> rake db:drop
+
+Create your database with:
+
+ $> rake db:create
+
+Migrate your database with:
+
+ $> rake db:migrate
+
+Create and migrate your database with
+
+ $> rake db:setup
+
+# Resources
+
+* [The Grapes of Rapid](http://www.confreaks.com/videos/475-rubyconf2010-the-grapes-of-rapid) - everything you need to know about Grape
+* [Building high-performance (Ruby) web services](http://www.confreaks.com/videos/653-gogaruco2011-0-60-with-goliath-building-high-performance-ruby-web-services) - everything you need to know about Goliath
+
+# Todo
+
+* Unify all the 'require' statements.
+* Make it work with databases other than Postgres
View
@@ -0,0 +1,47 @@
+require "rubygems"
+require "bundler/setup"
+require 'em-synchrony/activerecord'
+require 'yaml'
+require 'erb'
+
+namespace :db do
+ desc "loads database configuration in for other tasks to run"
+ task :load_config do
+ ActiveRecord::Base.configurations = db_conf
+
+ # drop and create need to be performed with a connection to the 'postgres' (system) database
+ ActiveRecord::Base.establish_connection db_conf["production"].merge('database' => 'postgres',
+ 'schema_search_path' => 'public')
+ end
+
+ desc "creates and migrates your database"
+ task :setup => :load_config do
+ Rake::Task["db:create"].invoke
+ Rake::Task["db:migrate"].invoke
+ end
+
+ desc "migrate your database"
+ task :migrate do
+ ActiveRecord::Base.establish_connection db_conf["production"]
+
+ ActiveRecord::Migrator.migrate(
+ ActiveRecord::Migrator.migrations_paths,
+ ENV["VERSION"] ? ENV["VERSION"].to_i : nil
+ )
+ end
+
+ desc 'Drops the database'
+ task :drop => :load_config do
+ ActiveRecord::Base.connection.drop_database db_conf['production']['database']
+ end
+
+ desc 'Creates the database'
+ task :create => :load_config do
+ ActiveRecord::Base.connection.create_database db_conf['production']['database']
+ end
+
+end
+
+def db_conf
+ config = YAML.load(ERB.new(File.read('config/database.yml')).result)
+end
View
@@ -0,0 +1,20 @@
+class PostsAPI < Grape::API
+
+ version 'v1', :using => :path
+ format :json
+
+ resource 'posts' do
+ get "/" do
+ Post.all
+ end
+
+ get "/:id" do
+ Post.find(params['id'])
+ end
+
+ post "/create" do
+ Post.create(params['post'])
+ end
+ end
+
+end
View
@@ -0,0 +1,5 @@
+class Post < ActiveRecord::Base
+
+ validates :title, :presence => true
+
+end
View
@@ -0,0 +1,22 @@
+require 'uri'
+require 'em-synchrony/activerecord'
+require 'yaml'
+require 'erb'
+
+# Sets up database configuration
+db = URI.parse(ENV['DATABASE_URL'] || 'http://localhost')
+if db.scheme == 'postgres' # Heroku environment
+ ActiveRecord::Base.establish_connection(
+ :adapter => db.scheme == 'postgres' ? 'postgresql' : db.scheme,
+ :host => db.host,
+ :username => db.user,
+ :password => db.password,
+ :database => db.path[1..-1],
+ :encoding => 'utf8'
+ )
+else # local environment
+ environment = ENV['DATABASE_URL'] ? 'production' : 'development'
+ db = YAML.load(ERB.new(File.read('config/database.yml')).result)[environment]
+ ActiveRecord::Base.establish_connection(db)
+end
+
View
@@ -0,0 +1,9 @@
+production: &production
+ adapter: em_postgresql
+ encoding: unicode
+ database: goliathgrape
+ pool: 5
+ username: root
+ password:
+development:
+ <<: *production
@@ -0,0 +1,11 @@
+class CreatePosts < ActiveRecord::Migration
+
+ def change
+ create_table :posts do |t|
+ t.string :title
+ t.text :body
+ t.timestamps
+ end
+ end
+
+end
View
@@ -0,0 +1,15 @@
+require "rubygems"
+require "bundler/setup"
+require 'goliath'
+require 'em-synchrony/activerecord'
+require 'grape'
+require './app/api/posts_api'
+require './app/models/post'
+
+class Application < Goliath::API
+
+ def response(env)
+ ::PostsAPI.call(env)
+ end
+
+end

0 comments on commit b14d1a0

Please sign in to comment.