-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit d39de51
Showing
10 changed files
with
471 additions
and
0 deletions.
There are no files selected for viewing
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# grape-vs-martini | ||
|
||
API server example to compare Ruby's [Grape](https://github.com/intridea/grape) Web Framwork to [Martini](https://github.com/codegangsta/martini) Web Framwork in Go | ||
|
||
And would respond to the following routes: | ||
|
||
GET /projects(.json) | ||
GET /project/:id(.json) | ||
|
||
Response format would be like: | ||
|
||
{"status": "Success", "data": [...]} | ||
{"status": "Fail", "error_message": "Bad api key"} | ||
|
||
An example `curl` command would be like: | ||
|
||
curl "http://127.0.0.1:8080/projects?key=61c2339c1bc92bc48120b55513cd568b" | ||
|
||
For Grape, port `9292` is used, and for Martini, port `8080` is used. | ||
|
||
## How to run the server | ||
|
||
### Grape Example | ||
|
||
Under `grape-example` folder. The API is mounted directly on Rack, using [puma](https://github.com/puma/puma) | ||
|
||
1. Modify database settings in `config.ru` | ||
|
||
2. Run `bundle` | ||
|
||
3. Run `rackup` | ||
|
||
### Martini Example | ||
|
||
Under `martini-example` folder | ||
|
||
1. Modify database settings in `server.go` file, change variables in `sql.Open()` | ||
|
||
2. Run `go run server.go entry.go` | ||
|
||
## How to create sample data | ||
|
||
Example uses MySQL as default database. | ||
|
||
Inside mysql, run: | ||
|
||
mysql> create database grape_vs_martini_api; | ||
|
||
Dump sample data into database: | ||
|
||
mysql -u root -p grape_vs_martini_api < grape_vs_martini_api.sql | ||
|
||
Sample data includes 10 companies, each with 50 projects, so there are 500 projects in total. | ||
|
||
Sample companies' api keys: | ||
|
||
61c2339c1bc92bc48120b55513cd568b | ||
bb27bc6b7330aaac63ac809df83311b8 | ||
e35402fa00728faf372abaf71623b7f4 | ||
bca4bf9d131ab311760c5b790c8568a5 | ||
49886a1c018496abb9ba4bf592c08d36 | ||
850eedd94a4d9a01962628faac7ace91 | ||
d036682c6ac91a41ac9eac064c02a43b | ||
77a767c39adc71fb241285309ff37ee5 | ||
75e82d812630bf6d9371339f3e634801 | ||
b5125eeabadcd5b3e55a76694d2b62b8 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
source 'http://rubygems.org' | ||
|
||
gem 'rack', '~> 1.4.5' | ||
gem 'json', '~> 1.8.1' | ||
gem 'grape', github: 'intridea/grape' | ||
gem 'grape-entity' | ||
gem 'mysql2' | ||
gem 'activerecord', '~> 3.2.15' | ||
gem 'puma' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
GIT | ||
remote: git://github.com/intridea/grape.git | ||
revision: bc0ad13ee2811a5d67a4c09c7c45dcc833a18429 | ||
specs: | ||
grape (0.7.0) | ||
activesupport | ||
builder | ||
hashie (>= 1.2.0) | ||
multi_json (>= 1.3.2) | ||
multi_xml (>= 0.5.2) | ||
rack (>= 1.3.0) | ||
rack-accept | ||
rack-mount | ||
virtus (>= 1.0.0) | ||
|
||
GEM | ||
remote: http://rubygems.org/ | ||
specs: | ||
activemodel (3.2.16) | ||
activesupport (= 3.2.16) | ||
builder (~> 3.0.0) | ||
activerecord (3.2.16) | ||
activemodel (= 3.2.16) | ||
activesupport (= 3.2.16) | ||
arel (~> 3.0.2) | ||
tzinfo (~> 0.3.29) | ||
activesupport (3.2.16) | ||
i18n (~> 0.6, >= 0.6.4) | ||
multi_json (~> 1.0) | ||
arel (3.0.3) | ||
axiom-types (0.0.5) | ||
descendants_tracker (~> 0.0.1) | ||
ice_nine (~> 0.9) | ||
builder (3.0.4) | ||
coercible (1.0.0) | ||
descendants_tracker (~> 0.0.1) | ||
descendants_tracker (0.0.3) | ||
equalizer (0.0.9) | ||
grape-entity (0.4.0) | ||
activesupport | ||
multi_json (>= 1.3.2) | ||
hashie (2.0.5) | ||
i18n (0.6.9) | ||
ice_nine (0.11.0) | ||
json (1.8.1) | ||
multi_json (1.8.4) | ||
multi_xml (0.5.5) | ||
mysql2 (0.3.15) | ||
puma (2.7.1) | ||
rack (>= 1.1, < 2.0) | ||
rack (1.4.5) | ||
rack-accept (0.4.5) | ||
rack (>= 0.4) | ||
rack-mount (0.8.3) | ||
rack (>= 1.0.0) | ||
tzinfo (0.3.38) | ||
virtus (1.0.1) | ||
axiom-types (~> 0.0.5) | ||
coercible (~> 1.0) | ||
descendants_tracker (~> 0.0.1) | ||
equalizer (~> 0.0.7) | ||
|
||
PLATFORMS | ||
ruby | ||
|
||
DEPENDENCIES | ||
activerecord (~> 3.2.15) | ||
grape! | ||
grape-entity | ||
json (~> 1.8.1) | ||
mysql2 | ||
puma | ||
rack (~> 1.4.5) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
require 'grape' | ||
module MySite | ||
class Project < ActiveRecord::Base | ||
belongs_to :company | ||
end | ||
|
||
class Company < ActiveRecord::Base | ||
has_many :projects | ||
end | ||
|
||
class API < Grape::API | ||
format :json | ||
default_format :json | ||
# prefix 'api' | ||
cascade false | ||
default_error_formatter :json | ||
|
||
helpers do | ||
def current_company | ||
key = params[:key] | ||
@current_company ||= Company.where(:api => key).first | ||
end | ||
|
||
def authenticate! | ||
error!({ "status" => "Fail", "error_message" => "Bad Key" }, 401) unless current_company | ||
end | ||
end | ||
|
||
rescue_from :all do |e| | ||
Rack::Response.new({ "status" => "Fail", "error_message" => e.message }.to_json, 405) | ||
end | ||
|
||
before do | ||
authenticate! | ||
end | ||
|
||
get "projects" do | ||
projects = current_company.projects | ||
present :data, projects, :with => APIEntities::Project | ||
present :status, "Success" | ||
end | ||
|
||
get "projects/:id" do | ||
project = current_company.projects.where(id: params[:id]).first | ||
if project | ||
{"data" => {"id" => project.id, "name" => project.name}, "status" => "Success"} | ||
else | ||
# error!({ "status" => "Fail", "error_message" => "Failed to save project" }, 404) | ||
{ "status" => "Fail", "error_message" => "Failed to save project" } | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
require 'active_record' | ||
Dir[File.dirname(__FILE__) + '/*.rb'].each {|f| require f} | ||
|
||
ActiveRecord::Base.establish_connection( | ||
:adapter => 'mysql2', | ||
:database => 'grape_vs_martini_api', | ||
:host => "127.0.0.1", | ||
:pool => 25, | ||
:username => "root", | ||
:password => "abc123" | ||
) | ||
#\ -s puma | ||
run MySite::API |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
require 'grape-entity' | ||
|
||
module MySite | ||
module APIEntities | ||
class Project < Grape::Entity | ||
expose :id | ||
expose :name | ||
end | ||
end | ||
end |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package main | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
_ "github.com/go-sql-driver/mysql" | ||
) | ||
|
||
type Project struct { | ||
Id int `json:"id"` | ||
Name string `json:"name"` | ||
} | ||
|
||
type Company struct { | ||
Id int `json:"id"` | ||
Api string `json:"api_key"` | ||
} | ||
|
||
func GetCompany(db *sql.DB, key string) (Company, int) { | ||
var company_id int | ||
var api_key string | ||
err := db.QueryRow("select id, api from companies where api = ? limit 1", key).Scan(&company_id, &api_key) | ||
switch { | ||
case err == sql.ErrNoRows: | ||
return Company{}, 0 | ||
case err != nil: | ||
fmt.Println(err) | ||
return Company{}, -1 | ||
default: | ||
return Company{company_id, api_key}, company_id | ||
} | ||
|
||
} | ||
|
||
func GetProject(db *sql.DB, company_id int, project_id int) (Project, int) { | ||
var ( | ||
id int | ||
name string | ||
) | ||
err := db.QueryRow("select id, name from projects where id = ? and company_id = ? limit 1", project_id, company_id).Scan(&id, &name) | ||
switch { | ||
case err == sql.ErrNoRows: | ||
return Project{}, 0 | ||
case err != nil: | ||
fmt.Println(err) | ||
return Project{}, -1 | ||
default: | ||
return Project{id, name}, id | ||
} | ||
|
||
} | ||
|
||
func GetProjects(db *sql.DB, companyId int) []Project { | ||
projects, err := db.Query("select id, name from projects where company_id = ?", companyId) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
|
||
var ( | ||
id int | ||
name string | ||
) | ||
|
||
p := make([]Project, 0) | ||
defer projects.Close() | ||
for projects.Next() { | ||
err := projects.Scan(&id, &name) | ||
if err != nil { | ||
fmt.Println(err) | ||
} else { | ||
p = append(p, Project{id, name}) | ||
} | ||
} | ||
return p | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
package main | ||
|
||
import ( | ||
"database/sql" | ||
"fmt" | ||
"github.com/codegangsta/martini" | ||
"github.com/codegangsta/martini-contrib/render" | ||
_ "github.com/go-sql-driver/mysql" | ||
"net/http" | ||
"strconv" | ||
) | ||
|
||
var db *sql.DB | ||
|
||
func main() { | ||
db, err := sql.Open("mysql", "root:abc123@tcp(127.0.0.1:3306)/grape_vs_martini_api") | ||
|
||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
defer db.Close() | ||
|
||
m := martini.Classic() | ||
m.Use(render.Renderer()) | ||
|
||
m.Use(func(res http.ResponseWriter, req *http.Request, r render.Render) { | ||
api_key := "" | ||
api_key = req.URL.Query().Get("key") | ||
if api_key == "" { | ||
r.JSON(404, map[string]interface{}{"status": "Fail", "error_message": "Need api key"}) | ||
} else { | ||
// r.JSON(200, map[string]interface{}{"key": api_key}) | ||
current_company, company_id := GetCompany(db, api_key) | ||
if company_id < 0 { | ||
r.JSON(404, map[string]interface{}{"status": "Fail", "error_message": "Bad api key"}) | ||
} else { | ||
m.Map(current_company) | ||
} | ||
} | ||
}) | ||
|
||
m.Get("/", func() string { | ||
return "Hello world!" | ||
}) | ||
|
||
m.Get("/projects", func(current_company Company, r render.Render) { | ||
projects := GetProjects(db, current_company.Id) | ||
r.JSON(200, map[string]interface{}{"status": "Success", "data": projects}) | ||
}) | ||
|
||
m.Get("/projects/:id", func(current_company Company, params martini.Params, r render.Render) { | ||
paramId, err := strconv.Atoi(params["id"]) | ||
if err != nil { | ||
r.JSON(404, map[string]interface{}{"status": "Fail", "error_message": err.Error()}) | ||
return | ||
} | ||
project, id := GetProject(db, current_company.Id, paramId) | ||
if id > 0 { | ||
r.JSON(200, map[string]interface{}{"status": "Success", "data": project}) | ||
} else { | ||
r.JSON(404, map[string]interface{}{"status": "Fail", "error_message": "Project not found"}) | ||
} | ||
}) | ||
|
||
// m.Run() | ||
http.ListenAndServe(":8080", m) | ||
} |