Commit d6f8e09e authored by Zac Wood's avatar Zac Wood

Moved from RSpec APi Docs to Apipie

this is sooooo much nicer and easier to work with
parent 902cbaca
Pipeline #2834 failed with stage
in 2 minutes and 4 seconds
......@@ -11,4 +11,3 @@ ENV RAILS_ENV production
RUN bundle install
RUN rails db:migrate
RUN rails db:seed
RUN rails docs:generate
......@@ -65,11 +65,4 @@ gem 'rubyXL'
# Linting
gem "rubocop", "~> 0.58.2"
# RSpec
gem 'rspec-rails'
# Generate API documentation
gem 'rspec_api_documentation'
# Pretty API docs
gem "apitome"
gem 'apipie-rails'
......@@ -40,9 +40,8 @@ GEM
tzinfo (~> 1.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
apitome (0.2.0)
kramdown
railties
apipie-rails (0.5.10)
rails (>= 4.1)
arel (8.0.0)
ast (2.4.0)
bindex (0.5.0)
......@@ -60,7 +59,6 @@ GEM
coderay (1.1.2)
concurrent-ruby (1.0.5)
crass (1.0.4)
diff-lcs (1.3)
erubi (1.7.1)
ffi (1.9.25)
globalid (0.4.1)
......@@ -74,7 +72,6 @@ GEM
jbuilder (2.7.0)
activesupport (>= 4.2.0)
multi_json (>= 1.2)
kramdown (1.17.0)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
......@@ -90,7 +87,6 @@ GEM
minitest (5.11.3)
multi_json (1.13.1)
multi_xml (0.6.0)
mustache (1.0.5)
nio4r (2.3.1)
nokogiri (1.8.3)
mini_portile2 (~> 2.3.0)
......@@ -138,31 +134,6 @@ GEM
rb-fsevent (0.10.3)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-core (3.8.0)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.0)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
rspec_api_documentation (6.0.0)
activesupport (>= 3.0.0)
mustache (~> 1.0, >= 0.99.4)
rspec (~> 3.0)
rubocop (0.58.2)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
......@@ -229,7 +200,7 @@ PLATFORMS
ruby
DEPENDENCIES
apitome
apipie-rails
byebug
capybara (~> 2.13)
httparty
......@@ -242,8 +213,6 @@ DEPENDENCIES
puma (~> 3.7)
rack-cors
rails (~> 5.1.6)
rspec-rails
rspec_api_documentation
rubocop (~> 0.58.2)
rubyXL
sass-rails (~> 5.0)
......
# Contains all actions having to do with CourseSections.
# This is a nested controller -- see +config/routes.rb+ for details
class CourseSectionsController < ApplicationController
# Render JSON of all Sections belonging to a given Course.
resource_description do
short 'Working with course sections, e.g. CS 112 001'
end
api :GET, '/courses_sections', 'Get a list of course sections'
param :course_id, Fixnum, desc: "Only get the course sections belonging to the course with this ID"
param :crn, String, desc: "Get the course section with this CRN"
def index
@sections = CourseSection.all
......
# Contains all actions having to do with Courses.
class CoursesController < ApplicationController
# Renders JSON of courses matching params.
resource_description do
short 'Working with courses, e.g. CS 112'
end
api :GET, '/courses', "Get a list of courses."
param :subject, String, desc: 'Course subject, e.g. "CS" or "ACCT"'
param :course_number, :number, desc: 'Course number, e.g. "112"'
def index
@courses = Course.all
......@@ -12,6 +18,8 @@ class CoursesController < ApplicationController
end
# Renders JSON of details of a singluar course, such as its sections
api :GET, '/courses/:id', "Get a list of all course sections for the course with the given id."
param :id, :number, desc: 'Course ID', required: true
def show
@sections = CourseSection.where(course_id: params[:id])
......
......@@ -3,8 +3,13 @@ require 'time'
# Contains functionality for generating schedules.
class SchedulesController < ApplicationController
resource_description do
short 'Endpoints for generating iCal files'
end
# Render an iCal file containing the schedules of all the
# course sections with the given CRNs.
api :GET, '/schedules', 'Generate an iCal file with events for the given CRNs'
param :crns, Array, of: String, desc: 'Array of CRNs to include as events in the calendar', required: true
def index
crns = params["crns"].split ','
@schedule = Schedule.new crns
......
Apipie.configure do |config|
config.app_name = "SRCT Schedules API"
config.api_base_url = "/api"
config.doc_base_url = "/api"
# where is your API defined?
config.api_controllers_matcher = "#{Rails.root}/app/controllers/**/*.rb"
config.api_routes = Rails.application.routes
# use Markdown for writing docs
config.markup = Apipie::Markup::Markdown.new
# Fixes annoying "can't find resource" bug, see https://github.com/Apipie/apipie-rails/issues/549
config.translate = false
config.default_locale = nil
config.app_info["1.0"] = "The SRCT Schedules API provides data about courses, sections, and professors offered at GMU."
end
Apitome.setup do |config|
# This determines where the Apitome routes will be mounted. Changing this to '/api/documentation' for instance would
# allow you to browse to http://localhost:3000/api/documentation to see your api documentation. Set to nil and mount
# it yourself if you need to.
config.mount_at = "/api"
# This defaults to Rails.root if left nil. If you're providing documentation for an engine using a dummy application
# it can be useful to set this to your engines root.. E.g. Application::Engine.root
config.root = nil
# This is where rspec_api_documentation outputs the JSON files. This is configurable within RAD, and so is
# configurable here.
config.doc_path = "doc/api"
# Set a parent controller that Apitome::DocsController inherits from. Useful if you want to use a custom
# `before_action`.
config.parent_controller = "ActionController::Base"
# The title of the documentation -- If your project has a name, you'll want to put it here.
config.title = "SRCT Schedules API"
# The main layout view for all documentation pages. By default this is pretty basic, but you may want to use your own
# application layout.
config.layout = "apitome/application"
# We're using highlight.js (https://github.com/isagalaev/highlight.js) for code highlighting, and it comes with some
# great themes. You can check http://softwaremaniacs.org/media/soft/highlight/test.html for themes, and enter the
# theme as lowercase/underscore.
config.code_theme = "default"
# This allows you to override the css manually. You typically want to require `apitome/application` within the
# override, but if you want to override it entirely you can do so.
config.css_override = nil
# This allows you to override the javascript manually. You typically want to require `apitome/application` within the
# override, but if you want to override it entirely you can do so.
config.js_override = nil
# You can provide a 'README' style markdown file for the documentation, which is a useful place to include general
# information. This path is relative to your doc_path configuration.
config.readme = "../api.md"
# Apitome can render the documentation into a single page that uses scrollspy, or it can render the documentation on
# individual pages on demand. This allows you to specify which one you want, as a single page may impact performance.
config.single_page = true
# You can specify how urls are formatted using a Proc or other callable object.
# Your proc will be called with a resource name or link, giving you the opportunity to modify it as necessary for in the documentation url.
config.url_formatter = ->(str) { str.gsub(/\.json$/, '').underscore.gsub(/[^0-9a-z\:]+/i, '-') }
# You can setup the docs to be loaded from a remote URL if they are
# not available in the application environment. This defaults to
# false.
config.remote_docs = false
# If the remote_docs is set to true, this URL is used as the base for
# the doc location. This should be the root of the doc location, where
# the readme is located. It uses the doc_path setting to build the
# URLs for the API documentation. This defaults to nil.
config.remote_url = nil
# If you would like to precompile your own assets, you can disable auto-compilation.
# This defaults to true
config.precompile_assets = true
end
RspecApiDocumentation.configure do |config|
# Output folder
config.docs_dir = Rails.root.join("doc", "api")
# An array of output format(s).
# Possible values are :json, :html, :combined_text, :combined_json,
# :json_iodocs, :textile, :markdown, :append_json
config.format = :JSON
config.request_headers_to_include = []
config.response_headers_to_include = []
end
......@@ -6,5 +6,6 @@ Rails.application.routes.draw do
resources :schedules, only: [:index]
end
get '/', to: redirect('/api')
apipie # sets up API docs
get '/', to: redirect('/api') # redirect the root url to API docs
end
Schedules API
=====================
Welcome to the SRCT Schedules API documentation. Here you can find descriptions and examples of all of the endpoints served.
{
"resource": "Course Sections",
"resource_explanation": "A way to search across the different course sections (i.e. CS 112 001, ECON 103 104) for each course",
"http_method": "GET",
"route": "/api/course_sections",
"description": "Search by course",
"explanation": null,
"parameters": [
{
"type": "number",
"name": "course_id",
"description": " course"
},
{
"type": "string",
"name": "crn",
"description": " crn"
}
],
"response_fields": [
],
"requests": [
{
"request_method": "GET",
"request_path": "/api/course_sections?course_id=169421928",
"request_body": null,
"request_headers": {
},
"request_query_parameters": {
"course_id": "169421928"
},
"request_content_type": null,
"response_status": 200,
"response_status_text": "OK",
"response_body": "[\n {\n \"id\": 91231435,\n \"name\": \"MyString\",\n \"crn\": \"MyString\",\n \"section_type\": \"MyString\",\n \"title\": \"MyString\",\n \"instructor\": \"MyString\",\n \"start_date\": \"2018-05-21\",\n \"end_date\": \"2018-06-04\",\n \"days\": \"MWF\",\n \"start_time\": \"12:00 pm\",\n \"end_time\": \"1:00 pm\",\n \"location\": \"MyString\",\n \"status\": \"MyString\",\n \"campus\": \"MyString\",\n \"notes\": \"MyString\",\n \"size_limit\": 1,\n \"course_id\": 169421928,\n \"created_at\": \"2018-09-02T18:29:10.904Z\",\n \"updated_at\": \"2018-09-02T18:29:10.904Z\"\n },\n {\n \"id\": 477709683,\n \"name\": \"MyString2\",\n \"crn\": \"MyString2\",\n \"section_type\": \"MyString\",\n \"title\": \"MyString\",\n \"instructor\": \"MyString\",\n \"start_date\": \"2018-05-21\",\n \"end_date\": \"2018-06-04\",\n \"days\": \"TR\",\n \"start_time\": \"11:00 am\",\n \"end_time\": \"2:00 pm\",\n \"location\": \"MyString\",\n \"status\": \"MyString\",\n \"campus\": \"MyString\",\n \"notes\": \"MyString\",\n \"size_limit\": 1,\n \"course_id\": 169421928,\n \"created_at\": \"2018-09-02T18:29:10.904Z\",\n \"updated_at\": \"2018-09-02T18:29:10.904Z\"\n }\n]",
"response_headers": {
},
"response_content_type": "application/json; charset=utf-8",
"curl": null
}
]
}
\ No newline at end of file
{
"resource": "Course Sections",
"resource_explanation": "A way to search across the different course sections (i.e. CS 112 001, ECON 103 104) for each course",
"http_method": "GET",
"route": "/api/course_sections",
"description": "Search by CRN",
"explanation": null,
"parameters": [
{
"type": "number",
"name": "course_id",
"description": " course"
},
{
"type": "string",
"name": "crn",
"description": " crn"
}
],
"response_fields": [
],
"requests": [
{
"request_method": "GET",
"request_path": "/api/course_sections?course_id=169421928&crn=70125",
"request_body": null,
"request_headers": {
},
"request_query_parameters": {
"course_id": "169421928",
"crn": "70125"
},
"request_content_type": null,
"response_status": 200,
"response_status_text": "OK",
"response_body": "[\n\n]",
"response_headers": {
},
"response_content_type": "application/json; charset=utf-8",
"curl": null
}
]
}
\ No newline at end of file
{
"resource": "Courses",
"resource_explanation": "A way to search across the different courses (i.e. CS 112, ECON 103) offered at GMU.",
"http_method": "GET",
"route": "/api/courses",
"description": "Filtered list of courses",
"explanation": null,
"parameters": [
{
"type": "string",
"name": "subject",
"description": " subject"
},
{
"type": "number",
"name": "course_number",
"description": " course number"
}
],
"response_fields": [
],
"requests": [
{
"request_method": "GET",
"request_path": "/api/courses?subject=CS&course_number=112",
"request_body": null,
"request_headers": {
},
"request_query_parameters": {
"subject": "CS",
"course_number": "112"
},
"request_content_type": null,
"response_status": 200,
"response_status_text": "OK",
"response_body": "[\n {\n \"id\": 169421928,\n \"subject\": \"CS\",\n \"course_number\": \"112\",\n \"semester_id\": 763694850,\n \"created_at\": \"2018-09-02T18:29:10.916Z\",\n \"updated_at\": \"2018-09-02T18:29:10.916Z\"\n }\n]",
"response_headers": {
},
"response_content_type": "application/json; charset=utf-8",
"curl": null
}
]
}
\ No newline at end of file
{
"resource": "Courses",
"resource_explanation": "A way to search across the different courses (i.e. CS 112, ECON 103) offered at GMU.",
"http_method": "GET",
"route": "/api/courses",
"description": "Listing all courses",
"explanation": null,
"parameters": [
],
"response_fields": [
],
"requests": [
{
"request_method": "GET",
"request_path": "/api/courses",
"request_body": null,
"request_headers": {
},
"request_query_parameters": {
},
"request_content_type": null,
"response_status": 200,
"response_status_text": "OK",
"response_body": "[\n {\n \"id\": 19883831,\n \"subject\": \"ACCT\",\n \"course_number\": \"110\",\n \"semester_id\": 938910979,\n \"created_at\": \"2018-09-02T18:29:10.916Z\",\n \"updated_at\": \"2018-09-02T18:29:10.916Z\"\n },\n {\n \"id\": 169421928,\n \"subject\": \"CS\",\n \"course_number\": \"112\",\n \"semester_id\": 763694850,\n \"created_at\": \"2018-09-02T18:29:10.916Z\",\n \"updated_at\": \"2018-09-02T18:29:10.916Z\"\n },\n {\n \"id\": 290898823,\n \"subject\": \"CS\",\n \"course_number\": \"211\",\n \"semester_id\": 763694850,\n \"created_at\": \"2018-09-02T18:29:10.916Z\",\n \"updated_at\": \"2018-09-02T18:29:10.916Z\"\n },\n {\n \"id\": 605506893,\n \"subject\": \"CS\",\n \"course_number\": \"110\",\n \"semester_id\": 938910979,\n \"created_at\": \"2018-09-02T18:29:10.916Z\",\n \"updated_at\": \"2018-09-02T18:29:10.916Z\"\n }\n]",
"response_headers": {
},
"response_content_type": "application/json; charset=utf-8",
"curl": null
}
]
}
\ No newline at end of file
{
"resources": [
{
"name": "Course Sections",
"explanation": "A way to search across the different course sections (i.e. CS 112 001, ECON 103 104) for each course",
"examples": [
{
"description": "Search by CRN",
"link": "course_sections/search_by_crn.json",
"groups": "all",
"route": "/api/course_sections",
"method": "get"
},
{
"description": "Search by course",
"link": "course_sections/search_by_course.json",
"groups": "all",
"route": "/api/course_sections",
"method": "get"
}
]
},
{
"name": "Courses",
"explanation": "A way to search across the different courses (i.e. CS 112, ECON 103) offered at GMU.",
"examples": [
{
"description": "Filtered list of courses",
"link": "courses/filtered_list_of_courses.json",
"groups": "all",
"route": "/api/courses",
"method": "get"
},
{
"description": "Listing all courses",
"link": "courses/listing_all_courses.json",
"groups": "all",
"route": "/api/courses",
"method": "get"
}
]
}
]
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
require 'rails_helper'
require 'rspec_api_documentation/dsl'
resource "Course Sections" do
explanation "A way to search across the different course sections (i.e. CS 112 001, ECON 103 104) for each course"
get "/api/course_sections" do
parameter :course_id, type: :number
parameter :crn, type: :string
context '200' do
let(:course_id) { 169421928 }
let(:crn) { "70125" }
example_request 'Search by CRN' do
expect(status).to eq(200)
end
end
context '200' do
let(:course_id) { 169421928 }
example_request 'Search by course' do
expect(status).to eq(200)
end
end
end
end
require 'rails_helper'
require 'rspec_api_documentation/dsl'
resource "Courses" do
explanation "A way to search across the different courses (i.e. CS 112, ECON 103) offered at GMU."
get "/api/courses" do
context '200' do
parameter :subject, type: :string
parameter :course_number, type: :number
let(:subject) { 'CS' }
let(:course_number) { 112 }
example_request 'Filtered list of courses' do
expect(status).to eq(200)
end
end
context '200' do
example_request 'Listing all courses' do
expect(status).to eq(200)
end
end
end
end
# This file is copied to spec/ when you run 'rails generate rspec:install'
require 'spec_helper'
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../config/environment', __dir__)
# Prevent database truncation if the environment is production
abort("The Rails environment is running in production mode!") if Rails.env.production?
require 'rspec/rails'
# Add additional requires below this line. Rails is not loaded until this point!
# Requires supporting ruby files with custom matchers and macros, etc, in
# spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
# run as spec files by default. This means that files in spec/support that end
# in _spec.rb will both be required and run as specs, causing the specs to be
# run twice. It is recommended that you do not name files matching this glob to
# end with _spec.rb. You can configure this pattern with the --pattern
# option on the command line or in ~/.rspec, .rspec or `.rspec-local`.
#
# The following line is provided for convenience purposes. It has the downside
# of increasing the boot-up time by auto-requiring all files in the support
# directory. Alternatively, in the individual `*_spec.rb` files, manually
# require only the support files necessary.
#
# Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each { |f| require f }
# Checks for pending migrations and applies them before tests are run.
# If you are not using ActiveRecord, you can remove these lines.
begin
ActiveRecord::Migration.maintain_test_schema!
rescue ActiveRecord::PendingMigrationError => e
puts e.to_s.strip
exit 1
end
RSpec.configure do |config|
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
# RSpec Rails can automatically mix in different behaviours to your tests
# based on their file location, for example enabling you to call `get` and
# `post` in specs under `spec/controllers`.
#
# You can disable this behaviour by removing the line below, and instead
# explicitly tag your specs with their type, e.g.:
#
# RSpec.describe UsersController, :type => :controller do
# # ...
# end
#
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
# Filter lines from Rails gems in backtraces.
config.filter_rails_from_backtrace!
# arbitrary gems may also be filtered via:
# config.filter_gems_from_backtrace("gem name")
end
# This file was generated by the `rails generate rspec:install` command. Conventionally, all
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
# The generated `.rspec` file contains `--require spec_helper` which will cause
# this file to always be loaded, without a need to explicitly require it in any
# files.
#
# Given that it is always loaded, you are encouraged to keep this file as
# light-weight as possible. Requiring heavyweight dependencies from this file
# will add to the boot time of your test suite on EVERY test run, even for an
# individual file that may not need all of that loaded. Instead, consider making
# a separate helper file that requires the additional dependencies and performs
# the additional setup, and require it from the spec files that actually need
# it.
#
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
RSpec.configure do |config|
# rspec-expectations config goes here. You can use an alternate
# assertion/expectation library such as wrong or the stdlib/minitest
# assertions if you prefer.
config.expect_with :rspec do |expectations|
# This option will default to `true` in RSpec 4. It makes the `description`
# and `failure_message` of custom matchers include text for helper methods
# defined using `chain`, e.g.:
# be_bigger_than(2).and_smaller_than(4).description
# # => "be bigger than 2 and smaller than 4"
# ...rather than:
# # => "be bigger than 2"
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
# rspec-mocks config goes here. You can use an alternate test double
# library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
# Prevents you from mocking or stubbing a method that does not exist on
# a real object. This is generally recommended, and will default to
# `true` in RSpec 4.
mocks.verify_partial_doubles = true
end
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
# have no way to turn it off -- the option exists only for backwards
# compatibility in RSpec 3). It causes shared context metadata to be
# inherited by the metadata hash of host groups and examples, rather than
# triggering implicit auto-inclusion in groups with matching metadata.
config.shared_context_metadata_behavior = :apply_to_host_groups
# The settings below are suggested to provide a good initial experience
# with RSpec, but feel free to customize to your heart's content.
# # This allows you to limit a spec run to individual examples or groups
# # you care about by tagging them with `:focus` metadata. When nothing
# # is tagged with `:focus`, all examples get run. RSpec also provides
# # aliases for `it`, `describe`, and `context` that include `:focus`
# # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
# config.filter_run_when_matching :focus
#
# # Allows RSpec to persist some state between runs in order to support
# # the `--only-failures` and `--next-failure` CLI options. We recommend
# # you configure your source control system to ignore this file.
# config.example_status_persistence_file_path = "spec/examples.txt"