Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/openapi #46

Merged
merged 50 commits into from
Aug 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
5fad2f5
First version of Dox 2.0
VKuzina Sep 25, 2019
8072adf
Added schemas, test fixing and changed output generation.
VKuzina Sep 27, 2019
be8fb63
Most specs changed and added funcionality of resources and groups
VKuzina Oct 1, 2019
a622118
Added descriptions for groups from md-files and fixed remaining depre…
VKuzina Oct 1, 2019
5c8a2d5
Referencing schemas now requires schema names in parameters of resour…
VKuzina Oct 2, 2019
6ac0b85
Fixed test for resources.
VKuzina Oct 2, 2019
45899d3
Made dox available for ruby 2.0 and up
VKuzina Oct 2, 2019
8a7eafe
Changed parameter forwarding in formatter and updated readme to be up…
VKuzina Oct 3, 2019
8c9c1a9
Fixed displaying of requests
VKuzina Oct 3, 2019
8ff2e2b
Changed readme
VKuzina Oct 4, 2019
f81f93f
Added destinction of loading descriptions through files and from string.
VKuzina Oct 4, 2019
e52f663
Changed header text, added parameters and their source, changed tests…
VKuzina Oct 14, 2019
74b5e12
Added response/request schema distinction, and refrencing is not prel…
VKuzina Oct 14, 2019
2a33af2
Added multiple example support and updated ruby version to 2.5.5
VKuzina Oct 15, 2019
d625597
Added aliases for resource(tag) and resource_group(x_tag)
VKuzina Oct 15, 2019
81c7139
Changed readme to better represent new api specification
VKuzina Oct 16, 2019
ddb9052
Changed schema location from resource to action, added request and su…
VKuzina Oct 21, 2019
70dde93
Returned data part of structue
VKuzina Oct 21, 2019
0c1fc0a
Added request and for each response header parameters.
VKuzina Oct 21, 2019
ca8ed37
Adjusted tests.
VKuzina Oct 21, 2019
b836985
Query parameters are now defined by user and not extracted anymore, t…
VKuzina Oct 21, 2019
50a6faf
Refactored code according to PR
VKuzina Oct 23, 2019
e2fff65
Changed features from PR.
VKuzina Oct 24, 2019
96d1c3c
Required rexml
VKuzina Oct 25, 2019
fd03aba
Changed requests from PR.
VKuzina Oct 25, 2019
f6595f3
Added deafult value to the read_file method
VKuzina Oct 25, 2019
84dc251
Only 1 header parameter example displayed per name, parameters added …
VKuzina Oct 28, 2019
d63ab32
Updated readme
VKuzina Oct 28, 2019
17d7e89
Default fail schema now given as full path, changed howheaders are ad…
VKuzina Oct 29, 2019
7842a88
Refactored the changing of response schemas and changed tests accordi…
VKuzina Oct 29, 2019
2203dfa
Enabled inline schema definition for requests, enabled nested paramet…
VKuzina Dec 16, 2019
fa659a3
Add query params
d4be4st Jan 3, 2020
7155368
Update Readme
d4be4st Jan 3, 2020
ae9a6f4
Update bundler version
d4be4st Jan 3, 2020
34fd3c8
Update travis config
d4be4st Jan 3, 2020
def5611
Update specs
d4be4st Jan 3, 2020
cc3b58f
Merge branch 'master' into feature/openapi
d4be4st Jan 3, 2020
2b8fb8a
changed success? to successful? for responses according to rails 6
VKuzina Feb 10, 2020
ee77663
Changed null descriptions to empty strings.
VKuzina Feb 10, 2020
c99f89c
Added 2.0 to changelog
VKuzina Feb 10, 2020
23434d8
Spec fix
VKuzina Feb 10, 2020
54bc213
Added BREAKING CHANGES marker in changelog.
VKuzina Feb 10, 2020
1860f3e
Changed wording in changelog.
VKuzina Feb 10, 2020
990a9b6
Able to add descriptions to actions now
VKuzina Feb 25, 2020
95c3caa
Enabled adding .md files as description for actions.
VKuzina Feb 25, 2020
3bb3d0c
Fix formatting file uploads
d4be4st Jun 9, 2020
cc13e52
Made configuration optional
d4be4st Aug 7, 2020
2c87b78
Auto add request and response metadata
d4be4st Aug 7, 2020
412d7a9
PR fixes
d4be4st Aug 7, 2020
af5b961
Update readme
d4be4st Aug 7, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ Documentation:
WordArray:
Enabled: False

AllCops:
TargetRubyVersion: 2.3

Style/FrozenStringLiteralComment:
Enabled: false

BlockLength:
Max: 250

Gemspec/RequiredRubyVersion:
Enabled: false
2 changes: 1 addition & 1 deletion .ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.3.1
2.5.5
18 changes: 7 additions & 11 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
language: ruby
before_install: gem install bundler -v 1.11.2
# before_install: gem install bundler -v 1.17.3

matrix:
include:
- rvm: 2.0.0
env: "RAILS_VERSION=4.0.0"
- rvm: 2.1.2
env: "RAILS_VERSION=4.1.0"
- rvm: 2.2.0
env: "RAILS_VERSION=4.2.0"
- rvm: 2.2.2
env: "RAILS_VERSION=5.0.0"
- rvm: 2.3.0
env: "RAILS_VERSION=5.0.0"
- rvm: 2.4.0
env: "RAILS_VERSION=5.0.0"
- rvm: 2.5.0
env: "RAILS_VERSION=5.0.0"
- rvm: 2.6.0
env: "RAILS_VERSION=6.0.0"
- rvm: 2.7.0
env: "RAILS_VERSION=6.0.0"

addons:
code_climate:
Expand Down
17 changes: 17 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# Changelog

## Version 2.0.0

Released on August 8, 2020

Change:
- BREAKING CHANGE The API description format changed from API-blueprint to OpenAPI.
- BREAKING CHANGE Base structure is now defined in .json format
- BREAKING CHANGE Output is written to a .json file
- BREAKING CHANGE Html is rendered with Redoc instead of Aglio
- Renamed Dox.config.desc_folder_path -> Dox.config.descriptions_location
- Depricated Dox.config.header_file_path

New:
- Added Dox.config.title
- Added Dox.config.header_description
- Added Dox.config.version

## Version 1.2.0

Released on November 27, 2019
Expand Down
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ source 'https://rubygems.org'
# Specify your gem's dependencies in dox.gemspec
gemspec

rails_version = ENV['RAILS_VERSION'] || '5.0.1'
rails_version = ENV['RAILS_VERSION'] || '6.0.2'

gem 'rails', "~> #{rails_version}"
198 changes: 90 additions & 108 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@

# Dox

Automate your documentation writing process! Dox generates API documentation from Rspec controller/request specs in a Rails application. It formats the test's output in the [API Blueprint](https://apiblueprint.org) format. Choose one of the [renderers](#renderers) to convert it to HTML or host it on [Apiary.io](https://apiary.io)
Automate your documentation writing process! Dox generates API documentation from Rspec controller/request specs in a Rails application. It formats the tests output in the [OpenApi](https://www.openapis.org/) format. Use the ReDoc renderer for generating and displaying the documentation as HTML.

Here's a [demo app](https://github.com/infinum/dox-demo) and here are some examples:

- [Dox demo - Apiary](http://docs.doxdemo.apiary.io/#reference/books/books)
- [Dox demo - Aglio](https://infinum.github.io/dox-demo/aglio)
- [Dox demo - Snowboard](https://infinum.github.io/dox-demo/snowboard)
Here's a [demo app](https://github.com/infinum/dox-demo).


## Installation
Expand Down Expand Up @@ -44,39 +40,33 @@ $ gem install dox
require 'dox'
```

and configure rspec with this:

``` ruby
RSpec.configure do |config|
config.after(:each, :dox) do |example|
example.metadata[:request] = request
example.metadata[:response] = response
end
end
```

### Configure it
Set these mandatory options in the rails_helper:
Set these optional options in the rails_helper:

| Option | Value | Description |
| -- | -- | -- |
| header_file_path | Pathname instance or fullpath string | Markdown file that will be included at the top of the documentation. It should contain title and some basic info about the api. |
| desc_folder_path | Pathname instance or fullpath string | Folder with markdown descriptions. |


Optional settings:

| Option | Value| Description |
| -- | -- | -- |
| descriptions_location | Pathname instance or fullpath string | Folder containing markdown descriptions of resources. |
| schema_request_folder_path | Pathname instance or fullpath string | Folder with request schemas of resources. |
| schema_response_folder_path | Pathname instance or fullpath string | Folder with response schemas of resources. |
| schema_response_fail_file_path | Pathname instance or fullpath string | Json file that contains the default schema of a failed response. |
| openapi_version | string | Openapi version (default: '3.0.0' ) |
| api_version | string | Api Version (default: '1.0') |
| title | string | Documentation title (default: 'API Documentation') |
| header_description | Pathname instance or string | Description (header) of the documentation (default: ''). If pathname ends with `.md`, the file is looked in `descriptions_location` folder |
| headers_whitelist | Array of headers (strings) | Requests and responses will by default list only `Content-Type` header. To list other http headers, you must whitelist them.|

Example:

``` ruby
Dox.configure do |config|
config.header_file_path = Rails.root.join('spec/docs/v1/descriptions/header.md')
config.desc_folder_path = Rails.root.join('spec/docs/v1/descriptions')
config.descriptions_location = Rails.root.join('spec/docs/v1/descriptions')
config.schema_request_folder_path = Rails.root.join('spec/docs/v1/schemas')
config.schema_response_folder_path = Rails.root.join('spec/support/v1/schemas')
config.schema_response_fail_file_path = Rails.root.join('spec/support/v1/schemas/error.json')
config.headers_whitelist = ['Accept', 'X-Auth-Token']
config.title = 'API'
config.api_version = '2.0'
config.header_description = 'api_description.md'
end
```

Expand All @@ -95,6 +85,7 @@ module Docs
resource 'Bids' do
endpoint '/bids'
group 'Bids'
desc 'bids.md'
end
end

Expand Down Expand Up @@ -138,34 +129,41 @@ And [generate the documentation](#generate-documentation).

### Advanced options

Before running into any more details, here's roughly how is the generated API Blueprint document structured:

- header
- resource group
- resource
- action
- example 1
- example 2
- action
- ...
- resource
- action
- ...
- resource group
- resource
- action


Header is defined in a markdown file as mentioned before. Examples are concrete test examples (you can have 2 examples for create 1 happy path, 1 fail path). They are completely automatically generated from the request/response objects.
Before running into any more details, here's roughly how the generated OpenApi document is structured:

- openapi
- info
- paths
- action 1
- tag1
- example 1
- example 2
- action 2
- tag2
- example 3
- x-tagGroups
- tags1
- tag 1
- tag 2
- tags2
- tag 3
- tag 4
- tags
d4be4st marked this conversation as resolved.
Show resolved Hide resolved
- tag1
- tag2


OpenApi and info are defined in a json file as mentioned before. Examples are concrete test examples (you can have multiple examples for both happy and fail paths). They are completely automatically generated from the request/response objects.
And you can customize the following in the descriptors:

- resource group
- resource
- x-tagGroup (**resourceGroup**)
- tag (**resource**)
- action
- example

#### Resource group
#### ResourceGroup

Resource group contains related resources and is defined with:
ResourceGroup contains related resources and is defined with:
- **name** (required)
- desc (optional, inline string or relative filepath)

Expand Down Expand Up @@ -198,7 +196,7 @@ document :bids do
end
```

Usually you'll want to define resource and resource group together, so you don't have to include 2 modules with common data per spec file:
Usually you'll want to define resourceGroup and resource together, so you don't have to include 2 modules with common data per spec file:

``` ruby
document :bids_common do
Expand All @@ -215,38 +213,66 @@ end
```

#### Action
Action is defined with:
Action contains examples and is defined with:
- **name** (required)
- path* (optional)
- verb* (optional)
- params* (optional)
- params (optional; _depricated_)
- query_params (optional; [more info](https://swagger.io/docs/specification/describing-parameters/#query-parameters))
- desc (optional; inline string or relative filepath)
- request_schema (optional; inline string or relative filepath)
- response_schema_success (optional; inline string or relative filepath)
- response_schema_fail (optional; inline string or relative filepath)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably be a global setting also.
In json api spec we need only one schema for errors because all are the same

So i would support both. If action response_schema_fail is not specified use a global one

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we really need to have the global setting, I think it should be optional, not required. I think it's required now.


\* these optional attributes are guessed (if not defined) from the request object of the test example and you can override them.

Example:

``` ruby
show_params = { id: { type: :number, required: :required, value: 1, description: 'bid id' } }
query_params = [ {
"in": "query",
"name": "filter",
"required": false,
"style": "deepObject",
"explode": true,
"schema": {
"type": "object",
"required": ["updated_at_gt"],
"example": {
"updated_at_gt": "2018-02-03 10:30:00"
},
"properties": {
"updated_at_gt": {
"type": "string",
"title": "date"
}
}
}
]

document :action do
action 'Get bid' do
path '/bids/{id}'
verb 'GET'
params show_params
query_params query_params
desc 'Some description for get bid action'
request_schema 'namespace/bids'
response_schema_success 'namespace/bids_s'
response_schema_fail 'namespace/bids_f'
end
end
```

### Generate documentation
Documentation is generated in 2 steps:

1. generate API Blueprint markdown:
```bundle exec rspec spec/controllers/api/v1 -f Dox::Formatter --order defined --tag dox --out docs.md```
1. generate OpenApi json file:
```bundle exec rspec --tag apidoc -f Dox::Formatter --order defined --tag dox --out spec/api_doc/v1/schemas/docs.json```

2. render HTML with some renderer, for example, with Aglio:
```aglio -i docs.md -o docs.html```
2. render HTML with Redoc:
```redoc-cli bundle -o public/api/docs/v2/docs.html spec/api_doc/v1/schemas/docs.json```


#### Use rake tasks
Expand All @@ -256,42 +282,32 @@ It's recommendable to write a few rake tasks to make things easier. Here's an ex
namespace :api do
namespace :doc do
desc 'Generate API documentation markdown'
task :md do
task :json do
require 'rspec/core/rake_task'

RSpec::Core::RakeTask.new(:api_spec) do |t|
t.pattern = 'spec/controllers/api/v1/'
t.rspec_opts = "-f Dox::Formatter --order defined --tag dox --out public/api/docs/v1/apispec.md"
t.rspec_opts = "-f Dox::Formatter --order defined --tag dox --out public/api/docs/v1/docs.json"
end

Rake::Task['api_spec'].invoke
end

task html: :md do
`aglio -i public/api/docs/v1/apispec.md -o public/api/docs/v1/index.html`
task html: :json do
`redoc-cli bundle -o public/api/docs/v2/index.html spec/api_doc/v1/schemas/docs.json`
end

task open: :html do
`open public/api/docs/v1/index.html`
end

task publish: :md do
`apiary publish --path=public/api/docs/v1/apispec.md --api-name=doxdemo`
end
end
end
```

#### Renderers
You can render the HTML yourself with one of the renderers:

- [Aglio](https://github.com/danielgtaylor/aglio)
- [Snowboard](https://github.com/subosito/snowboard)

Both support multiple themes and template customization.

Or you can just take your generated markdown and host your documentation on [Apiary.io](https://apiary.io).
You can render the HTML yourself with ReDoc:

- [Redoc](https://github.com/Redocly/redoc)

### Common issues

Expand All @@ -302,39 +318,6 @@ You might experience some strange issues when generating the documentation. Here
There seems to be a problem with **rspec-rails** versions 3.7 and later not automatically requiring the project's rails_helper.rb when run with the `--format` flag.

To fix this issue, generate your documentation with `--require rails_helper`:

```
bundle exec rspec -f Dox::Formatter --order defined --tag dox --out docs.md --require rails_helper
```

#### Wrap parameters issue
Rails wraps JSON parameters on all requests by default, which results with documented requests looking like this:

```
+ Request get pokemons
{
"pokemon": {}
}
```

To disable wrapping parameters with a resource name, turn off this feature in `config/initializers/wrap_parameters.rb`:

``` ruby
# Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array.
ActiveSupport.on_load(:action_controller) do
wrap_parameters format: []
end
```

#### Rendering warnings with Aglio
You might get the following warnings when rendering HTML with Aglio:

* `no headers specified (warning code 3)`
* `empty request message-body (warning code 6)`

This usually happens on GET requests examples when there are no headers. To solve this issue, add at least one header to the tests' requests, like `Accept: application/json`.


## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
Expand All @@ -354,4 +337,3 @@ Dox is maintained and sponsored by [Infinum](https://infinum.co).
## License

The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).

Loading