napa 0.1.29 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +13 -0
- data/README.md +46 -121
- data/Rakefile +2 -1
- data/docs/quickstart.md +292 -0
- data/lib/napa/active_record_extensions/stats.rb +46 -0
- data/lib/napa/cli.rb +20 -1
- data/lib/napa/generators/scaffold_generator.rb +5 -0
- data/lib/napa/generators/templates/api/app/apis/%name_tableize%_api.rb.tt +9 -9
- data/lib/napa/generators/templates/api/app/representers/%name_underscore%_representer.rb.tt +4 -0
- data/lib/napa/generators/templates/scaffold/.env.test.tt +1 -1
- data/lib/napa/generators/templates/scaffold/.env.tt +1 -1
- data/lib/napa/generators/templates/scaffold/.gitignore.tt +0 -2
- data/lib/napa/generators/templates/scaffold/.ruby-gemset.tt +1 -0
- data/lib/napa/generators/templates/scaffold/.ruby-version.tt +1 -0
- data/lib/napa/generators/templates/scaffold/{Gemfile → Gemfile.tt} +3 -2
- data/lib/napa/generators/templates/scaffold/app.rb +1 -1
- data/lib/napa/generators/templates/scaffold/config/database.yml.tt +18 -0
- data/lib/napa/generators/templates/scaffold/config.ru.tt +3 -0
- data/lib/napa/generators/templates/scaffold/db/schema.rb +11 -0
- data/lib/napa/generators/templates/scaffold/lib/.keep +0 -0
- data/lib/napa/grape_extensions/grape_helpers.rb +20 -0
- data/lib/napa/grape_extensions/representer.rb +12 -0
- data/lib/napa/middleware/request_stats.rb +3 -3
- data/lib/napa/version.rb +1 -1
- data/lib/napa.rb +2 -1
- data/lib/tasks/db.rake +17 -6
- data/lib/tasks/routes.rake +4 -11
- data/napa.gemspec +3 -1
- data/spec/active_record_extensions/stats_spec.rb +59 -0
- metadata +46 -9
- data/lib/napa/generators/templates/api/app/entities/%name_underscore%_entity.rb.tt +0 -7
- data/lib/napa/generators/templates/scaffold/config/database.yml +0 -18
- data/lib/napa/generators/templates/scaffold/console +0 -9
- data/lib/napa/grape_extensions/error_presenter.rb +0 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e1c303631113443a38699bded25a0f869222f86a
|
4
|
+
data.tar.gz: 33c810492456288eba6f4e0bfc041db253fa8aef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b7bb38860e58f64c4909d5647bb4f3d3ade3fb6f685cd3f0fdbdad72573018d316992068fd346b06d274e8bd3f7d872a6af364348efa699de66932f126c4a5c
|
7
|
+
data.tar.gz: 0c85828fa6035881434a92aa4d43d29103476d620233cab74ef951f68e1b3605b9e5cf9b4710a92a9c735f2153d8996f021d4db612f3a9d189182c33f372d50f
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
master
|
2
|
+
===
|
3
|
+
|
4
|
+
0.2.0
|
5
|
+
===
|
6
|
+
* The console is now run with `napa console`, added support for racksh
|
7
|
+
* Scaffold generator now supports the `--database (-d)` flag
|
8
|
+
* Scaffold generator now supports Mysql or Postgres with ActiveRecord
|
9
|
+
* Scaffold generator now uses Roar instead of Grape Entity
|
10
|
+
* Fixed a bug in `rake routes`
|
11
|
+
* Fixed a bug in `rake db:reset`
|
12
|
+
* Added StatsD instrumentation (experimental)
|
13
|
+
* Added a CHANGELOG
|
data/README.md
CHANGED
@@ -3,14 +3,7 @@
|
|
3
3
|
|
4
4
|
# Napa
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
* Generator
|
9
|
-
* Console
|
10
|
-
* Identity
|
11
|
-
* Logging
|
12
|
-
* Deployment
|
13
|
-
* Grape Specific Features (Cache management and Route inspection) i.e. `rake routes`
|
6
|
+
Napa is a simple framework for building Rack based APIs using Grape, Roar and ActiveRecord. It's designed to make it easy to quickly create and deploy new API services by providing **generators**, **middlewares** and a **console** similar to what you would expect from a Rails app.
|
14
7
|
|
15
8
|
## Installation
|
16
9
|
|
@@ -34,73 +27,72 @@ $ bundle install
|
|
34
27
|
|
35
28
|
## Getting Started
|
36
29
|
|
37
|
-
|
38
|
-
|
39
|
-
```
|
40
|
-
$ napa new your_project_name
|
41
|
-
```
|
30
|
+
See the [Quickstart Guide](https://github.com/bellycard/napa/blob/master/docs/quickstart.md) for an intro to creating a simple service with Napa.
|
42
31
|
|
43
|
-
|
32
|
+
## Usage
|
44
33
|
|
45
|
-
|
34
|
+
Run `napa` terminal prompt to see available features:
|
46
35
|
|
47
36
|
```
|
48
|
-
|
37
|
+
Commands:
|
38
|
+
napa console # Start the Napa console
|
39
|
+
napa generate api <api_name> # Create a Grape API, Model and Representer
|
40
|
+
napa generate migration <migration_name> # Create a Database Migration
|
41
|
+
napa help [COMMAND] # Describe available commands or one specific command
|
42
|
+
napa new <app_name> [app_path] # Create a scaffold for a new Napa service
|
43
|
+
napa version # Shows the Napa version number
|
49
44
|
```
|
50
45
|
|
51
|
-
2) Then, make sure your database connections are setup correctly. The configuration is set in the `.env` and `.env.test`. Then create your database by running:
|
52
46
|
|
53
|
-
|
54
|
-
|
55
|
-
```
|
56
|
-
|
57
|
-
3) Now you're ready to start up the server:
|
47
|
+
### Console
|
48
|
+
Similar to the Rails console, load an IRB sesson with your applications environment by running:
|
58
49
|
|
59
50
|
```
|
60
|
-
|
51
|
+
napa console
|
61
52
|
```
|
62
53
|
|
63
|
-
|
64
|
-
|
65
|
-
```
|
66
|
-
$ open http://127.0.0.1:9393/hello
|
67
|
-
```
|
54
|
+
### Rake Tasks
|
68
55
|
|
69
|
-
|
56
|
+
`rake -T` will give you a list of all available rake tasks:
|
70
57
|
|
71
58
|
```
|
72
|
-
|
73
|
-
|
74
|
-
|
59
|
+
rake db:create # Create the database
|
60
|
+
rake db:drop # Delete the database
|
61
|
+
rake db:migrate # Migrate the database through scripts in db/migrate
|
62
|
+
rake db:reset # Create the test database
|
63
|
+
rake db:schema:dump # Create a db/schema.rb file that can be portably used against any DB supported by AR
|
64
|
+
rake db:schema:load # Load a schema.rb file into the database
|
65
|
+
rake deploy:production # Deploy to production
|
66
|
+
rake deploy:staging # Deploy to staging
|
67
|
+
rake git:set_tag[tag] # Set tag, which triggers deploy
|
68
|
+
rake git:verify # Verify git repository is in a good state for deployment
|
69
|
+
rake routes # display all routes for Grape
|
75
70
|
```
|
76
71
|
|
77
|
-
|
72
|
+
## Middlewares
|
73
|
+
Napa includes a number of Rack middlewares that can be enabled to add functionality to your project.
|
78
74
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
75
|
+
### Authentication
|
76
|
+
The Authentication middleware will add a simple header based authentication layer to all requests. This is just looking for a header of `'Password' = 'Your Password'`. The passwords are defined in the `.env` file. You can allow multiple passwords by supplying a comma separated list. For example:
|
77
|
+
|
78
|
+
`HEADER_PASSWORDS='password1,password2'`
|
83
79
|
|
84
|
-
|
80
|
+
If your application doesn't require authentication, you can simply remove the middleware.
|
85
81
|
|
86
|
-
###
|
87
|
-
|
82
|
+
### Health Check
|
83
|
+
The Health Check middleware will add an endpoint at `/health` that will return some data about your app. This was created to allow monitoring tools a standardized way to monitor multiple services. This endpoint will return a response similar to this:
|
88
84
|
|
89
85
|
```
|
90
|
-
|
86
|
+
{
|
87
|
+
"name": "service-name",
|
88
|
+
"hostname": "host-name",
|
89
|
+
"revision": "current-git-sha-of-app",
|
90
|
+
"pid": 1234,
|
91
|
+
"parent_pid": 1233,
|
92
|
+
"napa_revision": "running-version-of-napa"
|
93
|
+
}
|
91
94
|
```
|
92
95
|
|
93
|
-
### Identity
|
94
|
-
The *Identity* module exists to provide and interface to get information about the application. For example:
|
95
|
-
|
96
|
-
`Napa::Identity.name` => Returns the name of the app defined by `ENV['SERVICE_NAME']`.
|
97
|
-
|
98
|
-
`Napa::Identity.hostname` => Returns the name of the host running the application.
|
99
|
-
|
100
|
-
`Napa::Identity.revision` => Returns the current revision from Git.
|
101
|
-
|
102
|
-
`Napa::Identity.pid` => Returns the current running process id.
|
103
|
-
|
104
96
|
### Logger
|
105
97
|
The *Logger* modules is used to create a common log format across applications. The Logger is enable via a rack middleware by adding the line below to your `config.ru` file:
|
106
98
|
|
@@ -120,70 +112,8 @@ ActiveRecord::Base.logger = Napa::Logger.logger
|
|
120
112
|
Napa::Logger.logger.debug 'Some Debug Message'
|
121
113
|
```
|
122
114
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
The tasks currently available are:
|
127
|
-
|
128
|
-
```ruby
|
129
|
-
rake deploy:staging
|
130
|
-
```
|
131
|
-
|
132
|
-
|
133
|
-
```ruby
|
134
|
-
rake deploy:production
|
135
|
-
```
|
136
|
-
|
137
|
-
**Please Note:** These tasks rely on two environment variables - `GITHUB_OAUTH_TOKEN` and `GITHUB_REPO`. For more information, see **Environment Variables** below.
|
138
|
-
|
139
|
-
### Grape Specific Features
|
140
|
-
At Belly we use the [Grape Micro-Framework](https://github.com/intridea/grape) for many services, so we've included a few common features.
|
141
|
-
|
142
|
-
#### Cache Managment
|
143
|
-
Cache control headers are sent with Grape API responses to prevent clients from caching responses unexpectedly. This feature is enabled by default, so you don't have to make any changes to enable it.
|
144
|
-
|
145
|
-
#### Route Inspection
|
146
|
-
A rake task is included to give you a Rails style list of your routes. Simpley run:
|
147
|
-
|
148
|
-
```ruby
|
149
|
-
rake routes
|
150
|
-
```
|
151
|
-
|
152
|
-
### Environment Variables
|
153
|
-
Napa expects to find some environment variables set in your application in order for some features to work. A list is below:
|
154
|
-
|
155
|
-
#### SERVICE_NAME
|
156
|
-
The name of your app or service, used by Identity and as a label for your logs
|
157
|
-
|
158
|
-
#### GITHUB\_OAUTH\_TOKEN
|
159
|
-
Used to grant access to your application on Github for deployment tagging
|
160
|
-
|
161
|
-
#### GITHUB_REPO
|
162
|
-
Your application's Github repo. i.e. `bellycard/napa`
|
163
|
-
|
164
|
-
## Middlewares
|
165
|
-
Napa includes a number of Rack middlewares that can be enabled to add functionality to your project.
|
166
|
-
|
167
|
-
### Authentication
|
168
|
-
The Authentication middleware will add a simple header based authentication layer to all requests. This is just looking for a header of `'Password' = 'Your Password'`. The passwords are defined in the `.env` file. You can allow multiple passwords by supplying a comma separated list. For example:
|
169
|
-
|
170
|
-
`HEADER_PASSWORDS='password1,password2'`
|
171
|
-
|
172
|
-
If your application doesn't require authentication, you can simply remove the middleware.
|
173
|
-
|
174
|
-
### Health Check
|
175
|
-
The Health Check middleware will add an endpoint at `/health` that will return some data about your app. This was created to allow monitoring tools a standardized way to monitor multiple services. This endpoint will return a response similar to this:
|
176
|
-
|
177
|
-
```
|
178
|
-
{
|
179
|
-
"name": "service-name",
|
180
|
-
"hostname": "host-name",
|
181
|
-
"revision": "current-git-sha-of-app",
|
182
|
-
"pid": 1234,
|
183
|
-
"parent_pid": 1233,
|
184
|
-
"napa_revision": "running-version-of-napa"
|
185
|
-
}
|
186
|
-
```
|
115
|
+
## Bugs & Feature Requests
|
116
|
+
Please add an issue in [Github](https://github.com/bellycard/napa/issues) if you discover a bug or have a feature request.
|
187
117
|
|
188
118
|
## Contributing
|
189
119
|
|
@@ -192,8 +122,3 @@ The Health Check middleware will add an endpoint at `/health` that will return s
|
|
192
122
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
193
123
|
4. Push to the branch (`git push origin my-new-feature`)
|
194
124
|
5. Create new Pull Request
|
195
|
-
|
196
|
-
|
197
|
-
## Todo/Feature Requests
|
198
|
-
|
199
|
-
* Add specs for logger and logging middleware
|
data/Rakefile
CHANGED
data/docs/quickstart.md
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
#Napa Quickstart
|
2
|
+
|
3
|
+
Napa was designed to make it easy to quickly create a new API service. Here we will cover the steps required to create a new simple API service using Napa, Grape, Roar and ActiveRecord.
|
4
|
+
|
5
|
+
Napa is available as a Ruby gem, to install it run:
|
6
|
+
|
7
|
+
```
|
8
|
+
gem install napa
|
9
|
+
```
|
10
|
+
|
11
|
+
## Service Scaffold
|
12
|
+
|
13
|
+
In this example we will create a new API to manage a directory of people. Each person will have a `name`, `job_title` and `email_address`. To get started, create a new scaffold by running:
|
14
|
+
|
15
|
+
```
|
16
|
+
napa new people_service
|
17
|
+
```
|
18
|
+
|
19
|
+
**Note:** by default, Napa will configure itself to use Mysql. If you prefer to use Postgres, simply pass in the `-d=pg` option to the `napa new` command.
|
20
|
+
|
21
|
+
You will see the following output:
|
22
|
+
|
23
|
+
```
|
24
|
+
Generating scaffold...
|
25
|
+
create people_service
|
26
|
+
create people_service/.env.test
|
27
|
+
create people_service/.env
|
28
|
+
create people_service/.gitignore
|
29
|
+
create people_service/.rubocop.yml
|
30
|
+
create people_service/.ruby-gemset
|
31
|
+
create people_service/.ruby-version
|
32
|
+
create people_service/Gemfile
|
33
|
+
create people_service/README.md
|
34
|
+
create people_service/Rakefile
|
35
|
+
create people_service/app.rb
|
36
|
+
create people_service/app/apis/application_api.rb
|
37
|
+
create people_service/app/apis/hello_api.rb
|
38
|
+
create people_service/config.ru
|
39
|
+
create people_service/config/database.yml
|
40
|
+
create people_service/config/initializers/active_record.rb
|
41
|
+
create people_service/config/middleware/honeybadger.rb
|
42
|
+
create people_service/db/schema.rb
|
43
|
+
create people_service/lib/.keep
|
44
|
+
create people_service/log/.gitkeep
|
45
|
+
create people_service/spec/apis/hello_api_spec.rb
|
46
|
+
create people_service/spec/factories/.gitkeep
|
47
|
+
create people_service/spec/spec_helper.rb
|
48
|
+
Done!
|
49
|
+
```
|
50
|
+
|
51
|
+
Now, change into the `people_service` directory and run Bundler to get all the gems you need:
|
52
|
+
|
53
|
+
```
|
54
|
+
bundle install
|
55
|
+
```
|
56
|
+
|
57
|
+
Once Bundler is done, you can create your databases by running:
|
58
|
+
|
59
|
+
```
|
60
|
+
rake db:reset
|
61
|
+
RACK_ENV=test rake db:reset
|
62
|
+
```
|
63
|
+
|
64
|
+
These tasks will look into the `.env` and `.env.test` files and drop, create and migrate the databases.
|
65
|
+
|
66
|
+
Once your databases are setup, you can run `rspec` to verify everything is working. The Napa generator includes a sample API and spec file in it's scaffold.
|
67
|
+
|
68
|
+
```
|
69
|
+
rspec spec
|
70
|
+
```
|
71
|
+
|
72
|
+
## API Generator
|
73
|
+
|
74
|
+
Now that we have our service scaffolded up, let's generate an API.
|
75
|
+
|
76
|
+
Napa include an API generator which will create a Grape API, Model and Representer by running:
|
77
|
+
|
78
|
+
```
|
79
|
+
napa generate api person
|
80
|
+
```
|
81
|
+
|
82
|
+
**Note:** the generator will pluralize the name of your resource for the API, so use the singular version in the generator.
|
83
|
+
|
84
|
+
You will see the following output:
|
85
|
+
|
86
|
+
```
|
87
|
+
Generating api...
|
88
|
+
create app/apis/people_api.rb
|
89
|
+
create app/models/person.rb
|
90
|
+
create app/representers/person_representer.rb
|
91
|
+
Done!
|
92
|
+
```
|
93
|
+
|
94
|
+
## Create a Person model
|
95
|
+
|
96
|
+
From the output above, we can see that the generated create a `Person` model, so we should create a migration to actually build the table for that in our database. So, let's run:
|
97
|
+
|
98
|
+
```
|
99
|
+
napa generate migration CreatePerson
|
100
|
+
```
|
101
|
+
|
102
|
+
You will see the following output:
|
103
|
+
|
104
|
+
```
|
105
|
+
Generating migration...
|
106
|
+
create db/migrate
|
107
|
+
create db/migrate/20140411163743_create_person.rb
|
108
|
+
Done!
|
109
|
+
```
|
110
|
+
|
111
|
+
Open up that migration file and add the migration to create the `people` table:
|
112
|
+
|
113
|
+
```ruby
|
114
|
+
class CreatePerson < ActiveRecord::Migration
|
115
|
+
def change
|
116
|
+
create_table :people do |t|
|
117
|
+
t.string :name
|
118
|
+
t.string :job_title
|
119
|
+
t.string :email
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
Then you can run:
|
126
|
+
|
127
|
+
```
|
128
|
+
rake db:migrate
|
129
|
+
```
|
130
|
+
|
131
|
+
## Declare these attributes in the API and Representer
|
132
|
+
|
133
|
+
To provide a more secure API, the Napa generator requires you to declare any parameters your API will accept. This is done in the `params` blocks related to the specific request. In this case we will want to declare the params in `people_api.rb` for `POST` and `PUT` to be:
|
134
|
+
|
135
|
+
### POST
|
136
|
+
|
137
|
+
```ruby
|
138
|
+
desc 'Create a person'
|
139
|
+
params do
|
140
|
+
optional :name, type: String, desc: 'The Name of the person'
|
141
|
+
optional :job_title, type: String, desc: 'The Job Title of the person'
|
142
|
+
optional :email, type: String, desc: 'The Email Address of the person'
|
143
|
+
end
|
144
|
+
```
|
145
|
+
|
146
|
+
### PUT
|
147
|
+
```ruby
|
148
|
+
desc 'Update a person'
|
149
|
+
params do
|
150
|
+
optional :name, type: String, desc: 'The Name of the person'
|
151
|
+
optional :job_title, type: String, desc: 'The Job Title of the person'
|
152
|
+
optional :email, type: String, desc: 'The Email Address of the person'
|
153
|
+
end
|
154
|
+
```
|
155
|
+
|
156
|
+
Then, finally, add these new fields to the `person_representer.rb` so they will be returned from the API response.
|
157
|
+
|
158
|
+
```ruby
|
159
|
+
class PersonRepresenter < Napa::Representer
|
160
|
+
property :id, type: String
|
161
|
+
property :name
|
162
|
+
property :job_title
|
163
|
+
property :email
|
164
|
+
end
|
165
|
+
```
|
166
|
+
|
167
|
+
## Wire it all up
|
168
|
+
|
169
|
+
The last thing you'll need to do is mount your new endpoint into the `ApplicationApi`. Your file will look like this:
|
170
|
+
|
171
|
+
```ruby
|
172
|
+
class ApplicationApi < Grape::API
|
173
|
+
format :json
|
174
|
+
extend Napa::GrapeExtenders
|
175
|
+
|
176
|
+
mount PeopleApi => '/people'
|
177
|
+
|
178
|
+
add_swagger_documentation
|
179
|
+
end
|
180
|
+
```
|
181
|
+
|
182
|
+
Tada, you now have an API!
|
183
|
+
|
184
|
+
## Send some requests
|
185
|
+
|
186
|
+
Now that the code is in place, let's start up the app and send it some requests.
|
187
|
+
|
188
|
+
Napa runs on Rack, so any rack based webserver will work. Shotgun is nice to use in development because it will reload your app on each request and you don't need to restart the server when there are changes.
|
189
|
+
|
190
|
+
Start the server on port 9393 by running:
|
191
|
+
|
192
|
+
```
|
193
|
+
shotgun
|
194
|
+
```
|
195
|
+
|
196
|
+
### POST /people
|
197
|
+
|
198
|
+
To create a person we will send a `POST` request to our API.
|
199
|
+
|
200
|
+
```
|
201
|
+
curl -X POST -d name="Darby Frey" -d job_title="Software Engineer" -d email="darbyfrey@gmail.com" http://localhost:9393/people
|
202
|
+
```
|
203
|
+
|
204
|
+
**SIDENOTE:** At this point, you will likely get an error response like the one below. By default Napa ships with the `Napa::Middleware::Authentication` enabled. For the purposes of this guide, we will disable this middleware to make the requests easier to construct. Be sure to re-enable this before you go to production. To disable the middleware, just comment out the `use Napa::Middleware::Authentication` line in `config.ru` and restart shotgun. Also, see the Napa::Middleware::Authentication docs for more details.
|
205
|
+
|
206
|
+
```json
|
207
|
+
{
|
208
|
+
"error": {
|
209
|
+
"code": "not_configured",
|
210
|
+
"message": "password not configured"
|
211
|
+
}
|
212
|
+
}
|
213
|
+
```
|
214
|
+
|
215
|
+
|
216
|
+
All response from Napa include the `data` key. In this case the newly created person object is returned nested within the `data` key.
|
217
|
+
|
218
|
+
```json
|
219
|
+
{
|
220
|
+
"data": {
|
221
|
+
"object_type": "person",
|
222
|
+
"id": "1",
|
223
|
+
"name": "Darby Frey",
|
224
|
+
"job_title": "Software Engineer",
|
225
|
+
"email": "darbyfrey@gmail.com"
|
226
|
+
}
|
227
|
+
}
|
228
|
+
```
|
229
|
+
|
230
|
+
### GET /people
|
231
|
+
|
232
|
+
```
|
233
|
+
curl -X GET http://localhost:9393/people
|
234
|
+
```
|
235
|
+
All response from Napa include the `data` key. In this case, we see an array containing just one user object.
|
236
|
+
|
237
|
+
```json
|
238
|
+
{
|
239
|
+
"data": [
|
240
|
+
{
|
241
|
+
"id": 1,
|
242
|
+
"name": "Darby Frey",
|
243
|
+
"job_title": "Software Engineer",
|
244
|
+
"email": "darbyfrey@gmail.com"
|
245
|
+
}
|
246
|
+
]
|
247
|
+
}
|
248
|
+
```
|
249
|
+
|
250
|
+
### GET /people/:person_id
|
251
|
+
|
252
|
+
```
|
253
|
+
curl -X GET http://localhost:9393/people/1
|
254
|
+
```
|
255
|
+
|
256
|
+
```json
|
257
|
+
{
|
258
|
+
"data": {
|
259
|
+
"object_type": "person",
|
260
|
+
"id": "1",
|
261
|
+
"name": "Darby Frey",
|
262
|
+
"job_title": "Software Engineer",
|
263
|
+
"email": "darbyfrey@gmail.com"
|
264
|
+
}
|
265
|
+
}
|
266
|
+
```
|
267
|
+
|
268
|
+
### PUT /people/:person_id
|
269
|
+
|
270
|
+
```
|
271
|
+
curl -X PUT -d job_title="Doctor Pepper" http://localhost:9393/people/1
|
272
|
+
```
|
273
|
+
|
274
|
+
```json
|
275
|
+
{
|
276
|
+
"data": {
|
277
|
+
"object_type": "person",
|
278
|
+
"id": "1",
|
279
|
+
"name": "Darby Frey",
|
280
|
+
"job_title": "Doctor Pepper",
|
281
|
+
"email": "darbyfrey@gmail.com"
|
282
|
+
}
|
283
|
+
}
|
284
|
+
```
|
285
|
+
|
286
|
+
So, there you have it, a new API service in minutes. It's very basic, but you can continue to build it out from here. One thing to note, we don't generate a `DELETE` request from the generator, but you can easily add that. The resources section below will link you to the Grape docs where you can find those instructions.
|
287
|
+
|
288
|
+
## Resources
|
289
|
+
|
290
|
+
* [Code Example: people-service](https://github.com/darbyfrey/people_service)
|
291
|
+
* [Grape](http://intridea.github.io/grape/)
|
292
|
+
* [Roar](https://github.com/apotonick/roar)
|
@@ -0,0 +1,46 @@
|
|
1
|
+
if defined?(ActiveSupport)
|
2
|
+
module Napa
|
3
|
+
module ActiveRecordStats
|
4
|
+
SQL_INSERT_DELETE_PARSER_REGEXP = /^(?<action>\w+)\s(\w+)\s\W*(?<table>\w+)/
|
5
|
+
SQL_SELECT_REGEXP = /select .*? FROM \W*(?<table>\w+)/i
|
6
|
+
SQL_UPDATE_REGEXP = /update \W*(?<table>\w+)/i
|
7
|
+
|
8
|
+
# Returns the table and query type
|
9
|
+
def self.extract_from_sql_inserts_deletes(query)
|
10
|
+
m = query.match(SQL_INSERT_DELETE_PARSER_REGEXP)
|
11
|
+
[m[:table], m[:action]]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.extract_sql_selects(query)
|
15
|
+
m = query.match(SQL_SELECT_REGEXP)
|
16
|
+
[m[:table], 'SELECT']
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.guess_sql_content(query)
|
20
|
+
m = query.match(SQL_UPDATE_REGEXP)
|
21
|
+
return [m[:table], 'UPDATE'] if m
|
22
|
+
unless m
|
23
|
+
m = query.match(SQL_SELECT_REGEXP)
|
24
|
+
extract_sql_selects(query) if m
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
ActiveSupport::Notifications.subscribe 'sql.active_record' do |name, start, finish, id, payload|
|
29
|
+
if payload[:name] == 'SQL'
|
30
|
+
table, action = extract_from_sql_inserts_deletes(payload[:sql])
|
31
|
+
elsif payload[:name] =~ /.* Load$/
|
32
|
+
table, action = extract_sql_selects(payload[:sql])
|
33
|
+
elsif !payload[:name]
|
34
|
+
table, action = guess_sql_content(payload[:sql])
|
35
|
+
end
|
36
|
+
|
37
|
+
if table
|
38
|
+
stat_context = "#{Thread.current[:stats_context] || Napa::Identity.name + '.unknown'}"
|
39
|
+
Napa::Stats.emitter.timing(
|
40
|
+
"#{stat_context}.sql.#{table}.#{action.downcase}.query_time",
|
41
|
+
(finish - start) * 1000)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/napa/cli.rb
CHANGED
@@ -28,6 +28,25 @@ module Napa
|
|
28
28
|
say Napa::VERSION
|
29
29
|
end
|
30
30
|
|
31
|
+
desc 'console', 'Start the Napa console'
|
32
|
+
def console
|
33
|
+
require 'racksh/init'
|
34
|
+
|
35
|
+
begin
|
36
|
+
require "pry"
|
37
|
+
interpreter = Pry
|
38
|
+
rescue LoadError
|
39
|
+
require "irb"
|
40
|
+
require "irb/completion"
|
41
|
+
interpreter = IRB
|
42
|
+
end
|
43
|
+
|
44
|
+
Rack::Shell.init
|
45
|
+
|
46
|
+
$0 = "#{$0} console"
|
47
|
+
interpreter.start
|
48
|
+
end
|
49
|
+
|
31
50
|
register(
|
32
51
|
Generators::ScaffoldGenerator,
|
33
52
|
'new',
|
@@ -35,7 +54,7 @@ module Napa
|
|
35
54
|
'Create a scaffold for a new Napa service'
|
36
55
|
)
|
37
56
|
|
38
|
-
desc "generate api <api_name>", "Create a Grape API, Model and
|
57
|
+
desc "generate api <api_name>", "Create a Grape API, Model and Representer"
|
39
58
|
subcommand "generate api", Napa::CLI::Generate
|
40
59
|
|
41
60
|
desc "generate migration <migration_name>", "Create a Database Migration"
|
@@ -10,10 +10,15 @@ module Napa
|
|
10
10
|
|
11
11
|
argument :app_name
|
12
12
|
argument :app_path, optional: true
|
13
|
+
class_option :database, default: 'mysql', aliases: '-d', desc: 'Preconfigure for selected database (options: mysql/postgres/pg)'
|
13
14
|
|
14
15
|
def generate
|
15
16
|
say 'Generating scaffold...'
|
16
17
|
|
18
|
+
@database_gem = ['pg','postgres'].include?(options[:database]) ? 'pg' : 'mysql2'
|
19
|
+
@database_adapter = ['pg','postgres'].include?(options[:database]) ? 'postgresql' : 'mysql2'
|
20
|
+
@database_user = ['pg','postgres'].include?(options[:database]) ? '' : 'root'
|
21
|
+
|
17
22
|
directory ".", (app_path || app_name)
|
18
23
|
|
19
24
|
say 'Done!', :green
|
@@ -1,41 +1,41 @@
|
|
1
1
|
class <%= name.classify.pluralize %>Api < Grape::API
|
2
|
-
desc 'Get a list of <%= name.underscore.tableize %>'
|
2
|
+
desc 'Get a list of <%= name.underscore.tableize %>'
|
3
3
|
params do
|
4
4
|
optional :ids, type: String, desc: 'comma separated <%= name.underscore %> ids'
|
5
5
|
end
|
6
6
|
get do
|
7
7
|
<%= name.underscore.tableize %> = <%= name.classify %>.filter(declared(params, include_missing: false))
|
8
|
-
|
8
|
+
represent <%= name.underscore.tableize %>, with: <%= name.classify %>Representer
|
9
9
|
end
|
10
10
|
|
11
|
-
desc 'Create an <%= name.underscore %>'
|
11
|
+
desc 'Create an <%= name.underscore %>'
|
12
12
|
params do
|
13
13
|
end
|
14
14
|
|
15
15
|
post do
|
16
16
|
<%= name.underscore %> = <%= name.classify %>.create(declared(params, include_missing: false))
|
17
17
|
error!(present_error(:record_invalid, <%= name.underscore %>.errors.full_messages)) unless <%= name.underscore %>.errors.empty?
|
18
|
-
|
18
|
+
represent <%= name.underscore %>, with: <%= name.classify %>Representer
|
19
19
|
end
|
20
20
|
|
21
21
|
params do
|
22
22
|
requires :id, desc: 'ID of the <%= name.underscore %>'
|
23
23
|
end
|
24
24
|
route_param :id do
|
25
|
-
desc 'Get an <%= name.underscore %>'
|
25
|
+
desc 'Get an <%= name.underscore %>'
|
26
26
|
get do
|
27
27
|
<%= name.underscore %> = <%= name.classify %>.find(params[:id])
|
28
|
-
|
28
|
+
represent <%= name.underscore %>, with: <%= name.classify %>Representer
|
29
29
|
end
|
30
30
|
|
31
|
-
desc 'Update an <%= name.underscore %>'
|
31
|
+
desc 'Update an <%= name.underscore %>'
|
32
32
|
params do
|
33
33
|
end
|
34
34
|
put do
|
35
35
|
# fetch <%= name.underscore %> record and update attributes. exceptions caught in app.rb
|
36
36
|
<%= name.underscore %> = <%= name.classify %>.find(params[:id])
|
37
|
-
<%= name.underscore %>.update_attributes!(declared(params, include_missing: false)
|
38
|
-
|
37
|
+
<%= name.underscore %>.update_attributes!(declared(params, include_missing: false))
|
38
|
+
represent <%= name.underscore %>, with: <%= name.classify %>Representer
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= app_name %>
|
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0
|
@@ -1,13 +1,14 @@
|
|
1
1
|
source 'https://rubygems.org'
|
2
|
+
ruby "2.0.0"
|
2
3
|
|
3
4
|
gem 'rack-cors'
|
4
|
-
gem '
|
5
|
+
gem '<%= @database_gem %>'
|
5
6
|
gem 'activerecord', '~> 4.0.0', :require => 'active_record'
|
6
7
|
gem 'honeybadger'
|
7
8
|
gem 'json'
|
8
9
|
gem 'shotgun'
|
9
10
|
gem 'napa'
|
10
|
-
gem '
|
11
|
+
gem 'roar'
|
11
12
|
gem 'grape-swagger'
|
12
13
|
|
13
14
|
group :development,:test do
|
@@ -15,5 +15,5 @@ Dir['./config/initializers/**/*.rb'].map { |file| require file }
|
|
15
15
|
Dir['./config/middleware/**/*.rb'].map { |file| require file }
|
16
16
|
|
17
17
|
# autoload app
|
18
|
-
relative_load_paths = %w[app/apis app/
|
18
|
+
relative_load_paths = %w[app/apis app/representers app/models app/workers lib]
|
19
19
|
ActiveSupport::Dependencies.autoload_paths += relative_load_paths
|
@@ -0,0 +1,18 @@
|
|
1
|
+
defaults: &defaults
|
2
|
+
adapter: <%= @database_adapter %>
|
3
|
+
host: <%%= ENV['DATABASE_HOST'] %>
|
4
|
+
username: <%%= ENV['DATABASE_USER'] %>
|
5
|
+
password: <%%= ENV['DATABASE_PASSWORD'] %>
|
6
|
+
database: <%%= ENV['DATABASE_NAME'] %>
|
7
|
+
|
8
|
+
production:
|
9
|
+
<<: *defaults
|
10
|
+
|
11
|
+
development:
|
12
|
+
<<: *defaults
|
13
|
+
|
14
|
+
test:
|
15
|
+
<<: *defaults
|
16
|
+
|
17
|
+
staging:
|
18
|
+
<<: *defaults
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# This file is auto-generated from the current state of the database. Instead
|
2
|
+
# of editing this file, please use the migrations feature of Active Record to
|
3
|
+
# incrementally modify your database, and then regenerate this schema definition.
|
4
|
+
#
|
5
|
+
# Note that this schema.rb definition is the authoritative source for your
|
6
|
+
# database schema. If you need to create the application database on another
|
7
|
+
# system, you should be using db:schema:load, not running all the migrations
|
8
|
+
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
|
9
|
+
# you'll amass, the slower it'll run and the greater likelihood for issues).
|
10
|
+
#
|
11
|
+
# It's strongly recommended that you check this file into your version control system.
|
File without changes
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Napa
|
2
|
+
module GrapeHelpers
|
3
|
+
def represent(data, with: nil, **args)
|
4
|
+
raise ArgumentError.new(":with option is required") if with.nil?
|
5
|
+
|
6
|
+
if data.respond_to?(:to_a)
|
7
|
+
return { data: data.each{ |item| with.new(item).to_hash(args) } }
|
8
|
+
else
|
9
|
+
return { data: with.new(data).to_hash(args)}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def present_error(code, message = '')
|
14
|
+
Napa::JsonError.new(code, message)
|
15
|
+
end
|
16
|
+
|
17
|
+
# extend all endpoints to include this
|
18
|
+
Grape::Endpoint.send :include, self
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'roar/decorator'
|
2
|
+
require 'roar/representer/json'
|
3
|
+
require 'roar/representer/feature/coercion'
|
4
|
+
|
5
|
+
module Napa
|
6
|
+
class Representer < Roar::Decorator
|
7
|
+
include Roar::Representer::JSON
|
8
|
+
include Representable::Coercion
|
9
|
+
|
10
|
+
property :object_type, getter: lambda { |*| self.class.name.underscore }
|
11
|
+
end
|
12
|
+
end
|
@@ -29,11 +29,11 @@ module Napa
|
|
29
29
|
|
30
30
|
request = Rack::Request.new(env)
|
31
31
|
path = normalize_path(request.path_info)
|
32
|
-
|
32
|
+
Thread.current[:stats_context] = "#{Napa::Identity.name}.http.#{request.request_method.downcase}.#{path}".gsub('/', '.')
|
33
33
|
|
34
34
|
# Emit stats to StatsD
|
35
|
-
Napa::Stats.emitter.increment(
|
36
|
-
Napa::Stats.emitter.timing(
|
35
|
+
Napa::Stats.emitter.increment(Thread.current[:stats_context] + '.requests')
|
36
|
+
Napa::Stats.emitter.timing(Thread.current[:stats_context] + '.response_time', response_time)
|
37
37
|
# Return the results
|
38
38
|
[status, headers, body]
|
39
39
|
end
|
data/lib/napa/version.rb
CHANGED
data/lib/napa.rb
CHANGED
@@ -17,8 +17,9 @@ require 'napa/json_error'
|
|
17
17
|
require 'napa/stats'
|
18
18
|
require 'napa/active_record_extensions/filter_by_hash'
|
19
19
|
require 'napa/grape_extensions/error_formatter'
|
20
|
-
require 'napa/grape_extensions/
|
20
|
+
require 'napa/grape_extensions/grape_helpers'
|
21
21
|
require 'napa/grape_extensions/entity'
|
22
|
+
require 'napa/grape_extensions/representer'
|
22
23
|
require 'napa/grape_extenders'
|
23
24
|
require 'napa/middleware/logger'
|
24
25
|
require 'napa/middleware/app_monitor'
|
data/lib/tasks/db.rake
CHANGED
@@ -16,17 +16,28 @@ unless defined?(Rails)
|
|
16
16
|
desc "Create the database"
|
17
17
|
task :create => :environment do
|
18
18
|
db = YAML.load(ERB.new(File.read('./config/database.yml')).result)[Napa.env]
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
|
20
|
+
options = {}.tap do |o|
|
21
|
+
o[:adapter] = db['adapter']
|
22
|
+
o[:database] = 'postgres' if db['adapter'] == 'postgres'
|
23
|
+
end
|
24
|
+
|
25
|
+
ActiveRecord::Base.establish_connection(options)
|
26
|
+
ActiveRecord::Base.connection.create_database(db['database'])
|
27
|
+
|
22
28
|
end
|
23
29
|
|
24
30
|
desc "Delete the database"
|
25
31
|
task :drop => :environment do
|
26
32
|
db = YAML.load(ERB.new(File.read('./config/database.yml')).result)[Napa.env]
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
|
34
|
+
options = {}.tap do |o|
|
35
|
+
o[:adapter] = db['adapter']
|
36
|
+
o[:database] = 'postgres' if db['adapter'] == 'postgres'
|
37
|
+
end
|
38
|
+
|
39
|
+
ActiveRecord::Base.establish_connection(options)
|
40
|
+
ActiveRecord::Base.connection.drop_database(db['database'])
|
30
41
|
end
|
31
42
|
|
32
43
|
desc "Create the test database"
|
data/lib/tasks/routes.rake
CHANGED
@@ -1,17 +1,10 @@
|
|
1
1
|
unless defined?(Rails)
|
2
2
|
desc "display all routes for Grape"
|
3
3
|
task :routes do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
false
|
9
|
-
end
|
10
|
-
end
|
11
|
-
grape_apis.each do |api|
|
12
|
-
api.routes.each do |r|
|
13
|
-
puts "#{r}"
|
14
|
-
end
|
4
|
+
ApplicationApi.routes.each do |api|
|
5
|
+
method = api.route_method.ljust(10)
|
6
|
+
path = api.route_path
|
7
|
+
puts " #{method} #{path}"
|
15
8
|
end
|
16
9
|
end
|
17
10
|
end
|
data/napa.gemspec
CHANGED
@@ -24,13 +24,15 @@ Gem::Specification.new do |gem|
|
|
24
24
|
gem.add_dependency 'virtus'
|
25
25
|
gem.add_dependency 'grape'
|
26
26
|
gem.add_dependency 'grape-swagger'
|
27
|
-
gem.add_dependency '
|
27
|
+
gem.add_dependency 'roar'
|
28
28
|
gem.add_dependency 'unicorn'
|
29
29
|
gem.add_dependency 'statsd-ruby'
|
30
|
+
gem.add_dependency 'racksh'
|
30
31
|
|
31
32
|
gem.add_development_dependency 'rspec'
|
32
33
|
gem.add_development_dependency 'pry'
|
33
34
|
gem.add_development_dependency 'git'
|
34
35
|
gem.add_development_dependency 'rubocop'
|
35
36
|
gem.add_development_dependency 'activerecord', '~>3.2.2'
|
37
|
+
gem.add_development_dependency 'sqlite3'
|
36
38
|
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'spec_helper'
|
3
|
+
require 'napa/active_record_extensions/stats.rb'
|
4
|
+
|
5
|
+
# Delete any prevous instantiations of the emitter and set valid statsd env vars
|
6
|
+
Napa::Stats.emitter = nil
|
7
|
+
ENV['STATSD_HOST'] = 'localhost'
|
8
|
+
ENV['STATSD_PORT'] = '8125'
|
9
|
+
|
10
|
+
ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
|
11
|
+
|
12
|
+
ActiveRecord::Schema.define(version: 1) do
|
13
|
+
create_table :foos do |t|
|
14
|
+
t.string :word
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Foo < ActiveRecord::Base
|
19
|
+
end
|
20
|
+
|
21
|
+
describe Napa::ActiveRecordStats do
|
22
|
+
before(:each) do
|
23
|
+
Foo.delete_all
|
24
|
+
@x = Foo.create(word: 'bar')
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should send a query_time for an insert' do
|
28
|
+
Napa::Stats.emitter.should_receive(:timing).with(
|
29
|
+
"#{Napa::Identity.name}.unknown.sql.foos.insert.query_time",
|
30
|
+
an_instance_of(Float)
|
31
|
+
)
|
32
|
+
Foo.create(word: 'baz')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should send a query_time for a select' do
|
36
|
+
Napa::Stats.emitter.should_receive(:timing).with(
|
37
|
+
"#{Napa::Identity.name}.unknown.sql.foos.select.query_time",
|
38
|
+
an_instance_of(Float)
|
39
|
+
)
|
40
|
+
Foo.all
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should send a query_time for a delete' do
|
44
|
+
Napa::Stats.emitter.should_receive(:timing).with(
|
45
|
+
"#{Napa::Identity.name}.unknown.sql.foos.delete.query_time",
|
46
|
+
an_instance_of(Float)
|
47
|
+
)
|
48
|
+
@x.delete
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should send a query_time for an update' do
|
52
|
+
Napa::Stats.emitter.should_receive(:timing).with(
|
53
|
+
"#{Napa::Identity.name}.unknown.sql.foos.update.query_time",
|
54
|
+
an_instance_of(Float)
|
55
|
+
)
|
56
|
+
@x.word = 'baz'
|
57
|
+
@x.save
|
58
|
+
end
|
59
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: napa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Darby Frey
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-04-
|
11
|
+
date: 2014-04-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -123,7 +123,7 @@ dependencies:
|
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
-
name:
|
126
|
+
name: roar
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
129
|
- - '>='
|
@@ -164,6 +164,20 @@ dependencies:
|
|
164
164
|
- - '>='
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: racksh
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - '>='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - '>='
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
167
181
|
- !ruby/object:Gem::Dependency
|
168
182
|
name: rspec
|
169
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -234,6 +248,20 @@ dependencies:
|
|
234
248
|
- - ~>
|
235
249
|
- !ruby/object:Gem::Version
|
236
250
|
version: 3.2.2
|
251
|
+
- !ruby/object:Gem::Dependency
|
252
|
+
name: sqlite3
|
253
|
+
requirement: !ruby/object:Gem::Requirement
|
254
|
+
requirements:
|
255
|
+
- - '>='
|
256
|
+
- !ruby/object:Gem::Version
|
257
|
+
version: '0'
|
258
|
+
type: :development
|
259
|
+
prerelease: false
|
260
|
+
version_requirements: !ruby/object:Gem::Requirement
|
261
|
+
requirements:
|
262
|
+
- - '>='
|
263
|
+
- !ruby/object:Gem::Version
|
264
|
+
version: '0'
|
237
265
|
description: A simple framework for building APIs with Grape
|
238
266
|
email:
|
239
267
|
- darby@bellycard.com
|
@@ -245,13 +273,16 @@ files:
|
|
245
273
|
- .gitignore
|
246
274
|
- .rubocop.yml
|
247
275
|
- .travis.yml
|
276
|
+
- CHANGELOG.md
|
248
277
|
- Gemfile
|
249
278
|
- LICENSE
|
250
279
|
- README.md
|
251
280
|
- Rakefile
|
252
281
|
- bin/napa
|
282
|
+
- docs/quickstart.md
|
253
283
|
- lib/napa.rb
|
254
284
|
- lib/napa/active_record_extensions/filter_by_hash.rb
|
285
|
+
- lib/napa/active_record_extensions/stats.rb
|
255
286
|
- lib/napa/authentication.rb
|
256
287
|
- lib/napa/cli.rb
|
257
288
|
- lib/napa/generators.rb
|
@@ -259,24 +290,27 @@ files:
|
|
259
290
|
- lib/napa/generators/migration_generator.rb
|
260
291
|
- lib/napa/generators/scaffold_generator.rb
|
261
292
|
- lib/napa/generators/templates/api/app/apis/%name_tableize%_api.rb.tt
|
262
|
-
- lib/napa/generators/templates/api/app/entities/%name_underscore%_entity.rb.tt
|
263
293
|
- lib/napa/generators/templates/api/app/models/%name_underscore%.rb.tt
|
294
|
+
- lib/napa/generators/templates/api/app/representers/%name_underscore%_representer.rb.tt
|
264
295
|
- lib/napa/generators/templates/migration/%migration_filename%.rb.tt
|
265
296
|
- lib/napa/generators/templates/scaffold/.env.test.tt
|
266
297
|
- lib/napa/generators/templates/scaffold/.env.tt
|
267
298
|
- lib/napa/generators/templates/scaffold/.gitignore.tt
|
268
299
|
- lib/napa/generators/templates/scaffold/.rubocop.yml
|
269
|
-
- lib/napa/generators/templates/scaffold
|
300
|
+
- lib/napa/generators/templates/scaffold/.ruby-gemset.tt
|
301
|
+
- lib/napa/generators/templates/scaffold/.ruby-version.tt
|
302
|
+
- lib/napa/generators/templates/scaffold/Gemfile.tt
|
270
303
|
- lib/napa/generators/templates/scaffold/README.md
|
271
304
|
- lib/napa/generators/templates/scaffold/Rakefile
|
272
305
|
- lib/napa/generators/templates/scaffold/app.rb
|
273
306
|
- lib/napa/generators/templates/scaffold/app/apis/application_api.rb
|
274
307
|
- lib/napa/generators/templates/scaffold/app/apis/hello_api.rb.tt
|
275
308
|
- lib/napa/generators/templates/scaffold/config.ru.tt
|
276
|
-
- lib/napa/generators/templates/scaffold/config/database.yml
|
309
|
+
- lib/napa/generators/templates/scaffold/config/database.yml.tt
|
277
310
|
- lib/napa/generators/templates/scaffold/config/initializers/active_record.rb
|
278
311
|
- lib/napa/generators/templates/scaffold/config/middleware/honeybadger.rb
|
279
|
-
- lib/napa/generators/templates/scaffold/
|
312
|
+
- lib/napa/generators/templates/scaffold/db/schema.rb
|
313
|
+
- lib/napa/generators/templates/scaffold/lib/.keep
|
280
314
|
- lib/napa/generators/templates/scaffold/log/.gitkeep
|
281
315
|
- lib/napa/generators/templates/scaffold/spec/apis/hello_api_spec.rb.tt
|
282
316
|
- lib/napa/generators/templates/scaffold/spec/factories/.gitkeep
|
@@ -284,7 +318,8 @@ files:
|
|
284
318
|
- lib/napa/grape_extenders.rb
|
285
319
|
- lib/napa/grape_extensions/entity.rb
|
286
320
|
- lib/napa/grape_extensions/error_formatter.rb
|
287
|
-
- lib/napa/grape_extensions/
|
321
|
+
- lib/napa/grape_extensions/grape_helpers.rb
|
322
|
+
- lib/napa/grape_extensions/representer.rb
|
288
323
|
- lib/napa/identity.rb
|
289
324
|
- lib/napa/json_error.rb
|
290
325
|
- lib/napa/logger/log_transaction.rb
|
@@ -303,6 +338,7 @@ files:
|
|
303
338
|
- lib/tasks/routes.rake
|
304
339
|
- napa.gemspec
|
305
340
|
- spec/active_record_extensions/filter_by_hash_spec.rb
|
341
|
+
- spec/active_record_extensions/stats_spec.rb
|
306
342
|
- spec/authentication_spec.rb
|
307
343
|
- spec/grape_extensions/error_formatter_spec.rb
|
308
344
|
- spec/identity_spec.rb
|
@@ -333,12 +369,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
333
369
|
version: '0'
|
334
370
|
requirements: []
|
335
371
|
rubyforge_project:
|
336
|
-
rubygems_version: 2.
|
372
|
+
rubygems_version: 2.2.2
|
337
373
|
signing_key:
|
338
374
|
specification_version: 4
|
339
375
|
summary: A simple framework for building APIs with Grape
|
340
376
|
test_files:
|
341
377
|
- spec/active_record_extensions/filter_by_hash_spec.rb
|
378
|
+
- spec/active_record_extensions/stats_spec.rb
|
342
379
|
- spec/authentication_spec.rb
|
343
380
|
- spec/grape_extensions/error_formatter_spec.rb
|
344
381
|
- spec/identity_spec.rb
|
@@ -1,7 +0,0 @@
|
|
1
|
-
class <%= name.classify %>Entity < Napa::Entity
|
2
|
-
root :data, :data
|
3
|
-
expose :id, proc: lambda { |o, opts| o.id.to_s }, documentation:
|
4
|
-
{ type: 'String', description: 'ID' }
|
5
|
-
expose :type, proc: lambda { |o, opts| o.class.name.underscore }, documentation:
|
6
|
-
{ type: 'String', description: '"<%= name.underscore %>"' }
|
7
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
defaults: &defaults
|
2
|
-
adapter: mysql2
|
3
|
-
host: <%= ENV['DATABASE_HOST'] %>
|
4
|
-
username: <%= ENV['DATABASE_USER'] %>
|
5
|
-
password: <%= ENV['DATABASE_PASSWORD'] %>
|
6
|
-
database: <%= ENV['DATABASE_NAME'] %>
|
7
|
-
|
8
|
-
production:
|
9
|
-
<<: *defaults
|
10
|
-
|
11
|
-
development:
|
12
|
-
<<: *defaults
|
13
|
-
|
14
|
-
test:
|
15
|
-
<<: *defaults
|
16
|
-
|
17
|
-
staging:
|
18
|
-
<<: *defaults
|