Skip to content

Commit

Permalink
Improved documentation and purpose in README.md (#1)
Browse files Browse the repository at this point in the history
* Improved documentation and purpose in README.md

* README.md updated

* Version updated to 0.5.1.beta1
  • Loading branch information
abhisheksarka authored Sep 10, 2024
1 parent 97fee9f commit be1f601
Show file tree
Hide file tree
Showing 11 changed files with 252 additions and 58 deletions.
16 changes: 11 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

🚀 Accelerates your development by 2-3x with an API Design First approach. Seamlessly integrates with your Rails application server — no fancy tooling or expenses required.

We believe that API contracts should lead the development process, not be an afterthought derived from code. This framework embraces the [**API Design-First philosophy**](#-api-design-first-philosophy), ensuring that contracts remain independent from implementation.

With APICraft, contracts are not only clear and consistent, but they’re also immediately usable, enabling teams to work with automatically generated mocks, behaviours and introspection tools, allowing development to begin in parallel, without waiting for backend implementations.

It avoids the pitfalls of the code-first methodology, where contracts are auto-generated, often leading to inconsistency and misalignment.

![APICraft Rails Logo](assets/apicraft_rails.png)

- [APICraft Rails (Beta)](#apicraft-rails-beta)
Expand All @@ -16,7 +22,7 @@
- [🎭 API Mocking](#-api-mocking)
- [🎮 API Mocking (Behaviours)](#-api-mocking-behaviours)
- [🧐 API Introspection](#-api-introspection)
- [📖 API Documentation (Swagger docs and Redoc)](#-api-documentation-swagger-docs-and-redoc)
- [📖 API Documentation (Swagger docs and RapiDoc)](#-api-documentation-swagger-docs-and-rapidoc)
- [🔧 Configuration](#-configuration)
- [🤝 Contributing](#-contributing)
- [📝 License](#-license)
Expand All @@ -29,7 +35,7 @@

- 🔍 **API Introspections** - Introspect API schemas without needing to dig into the docs everytime.

- 📺 **Documentation Out of the Box** - Documentation using `SwaggerDoc` and `Redoc` both.
- 📺 **Documentation Out of the Box** - Documentation using `SwaggerDoc` and `RapiDoc` both.

- 🗂 **Easy Contracts Management** - Management of `openapi` specifications from within `app/contracts` directory. No new syntax, just plain old `openapi` standard with `.json` or `.yaml` formats

Expand Down Expand Up @@ -66,7 +72,7 @@ By adopting an API Design First approach with APICraft Rails, you can accelerate
Add this line to your application's Gemfile:

```ruby
gem 'apicraft-rails', '~> 0.5.0.beta1'
gem 'apicraft-rails', '~> 0.5.1.beta1'
```

And then execute:
Expand Down Expand Up @@ -187,7 +193,7 @@ Example: `https://yoursite.com/api/orders`
}
}
```
### 📖 API Documentation (Swagger docs and Redoc)
### 📖 API Documentation (Swagger docs and RapiDoc)

Mount the documentation views in your route file.

Expand All @@ -202,7 +208,7 @@ end

You can browse API Documentation at
- `/apicraft/swaggerdoc`
- `/apicraft/redoc`
- `/apicraft/rapidoc`

Enable authentication for the `/apicraft` namespace.

Expand Down
2 changes: 1 addition & 1 deletion lib/apicraft/version.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

# Current version of Apicraft.
module Apicraft
VERSION = "0.5.0.beta1"
VERSION = "0.5.1.beta1"
end
37 changes: 10 additions & 27 deletions lib/apicraft/web/actions.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@ module Web
# Web actions to be handled from
# the rack app.
module Actions
def self.index(view_path)
[
File.read(view_path),
"text/html"
]
end

def self.swaggerdoc(view_path)
def self.render_erb(view_path)
@vars = {
urls: Router.contract_urls
urls: Router.contract_urls,
namespace: Router.namespace,
version: Apicraft::VERSION
}

[
Expand All @@ -25,16 +20,10 @@ def self.swaggerdoc(view_path)
]
end

def self.redoc(view_path)
@vars = {
urls: Router.contract_urls
}

def self.images(view_path)
[
ERB.new(
File.read(view_path)
).result(binding),
"text/html"
File.read(view_path),
mime_type(view_path)
]
end

Expand All @@ -45,15 +34,9 @@ def self.contract(view_path)
]
end

def self.introspect(method, view_path)
[
Apicraft::Openapi::Contract.find_by_operation(
method, view_path
)&.operation(
method, view_path
)&.raw_schema&.to_json,
"application/json"
]
def self.mime_type(view_path)
ext = File.extname(view_path)
Rack::Mime.mime_type(ext)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions lib/apicraft/web/app.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ def self.call(env)
Router.namespace = env["SCRIPT_NAME"]
path = uri.split(
Router.namespace
)[-1]
)[-1] || "/"

content, content_type = Router.load_response!(
method, path || "/"
method, path
)

raise Errors::RouteNotFound if content.nil?
Expand Down
25 changes: 18 additions & 7 deletions lib/apicraft/web/router.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,33 @@ module Router
WEB_ROOT = File.expand_path(
"#{File.dirname(__FILE__)}/../../../web"
)
IMAGES_DIR = "#{WEB_ROOT}/assets/images"

def self.routes
@routes ||= {
"/": {
action: :index,
view_path: "#{WEB_ROOT}/views/index.html"
action: :render_erb,
view_path: "#{WEB_ROOT}/views/index.erb"
},
"/swaggerdoc": {
action: :swaggerdoc,
action: :render_erb,
view_path: "#{WEB_ROOT}/views/swaggerdoc.erb"
},
"/redoc": {
action: :redoc,
action: :render_erb,
view_path: "#{WEB_ROOT}/views/redoc.erb"
},
"/rapidoc": {
action: :render_erb,
view_path: "#{WEB_ROOT}/views/rapidoc.erb"
},
"/assets/images/thumb.png": {
action: :images,
view_path: "#{IMAGES_DIR}/apicraft_thumb.png"
},
"/assets/images/logo.png": {
action: :images,
view_path: "#{IMAGES_DIR}/apicraft.png"
}
}.with_indifferent_access
end
Expand All @@ -32,9 +45,7 @@ def self.add(path, view_path)
}
end

def self.load_response!(method, path)
return Actions.introspect(method, path) unless routes[path].present?

def self.load_response!(_method, path)
Actions.send(
routes[path][:action],
routes[path][:view_path]
Expand Down
Binary file added web/assets/images/apicraft.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added web/assets/images/apicraft_thumb.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
83 changes: 83 additions & 0 deletions web/views/index.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<title>APICraft</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<style>
body {
margin: 0;
padding-top: 40px;
font-family: 'Montserrat', 'Roboto', sans-serif;
background-color: #121212;
position: relative;
}
#container {
margin-top: 60px;
text-align: center;
max-width: 550px;
margin-left: auto;
margin-right: auto;
color: white;
}
.muted {
opacity: 0.5;
}
.primary-btn {
background-color: #4C2A85;
color: white;
padding: 10px 20px;
text-decoration: none;
border-radius: 5px;
font-size: 16px;
display: inline-block;
cursor: pointer;
transition: background-color 0.3s ease;
}

.primary-btn:hover {
background-color: #3A2064;
}

.github-btn {
background-color: white;
color: #4C2A85;
padding: 5px 10px;
text-decoration: none;
border-radius: 5px;
font-size: 12px;
display: inline-block;
border: 2px solid #4C2A85;
cursor: pointer;
transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.github-btn:hover {
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
}
</style>
</head>
<body>
<div id="container">
<img src="<%= @vars[:namespace] %>/assets/images/logo.png" height="120" width="120"/>
<p>Welcome to <strong>API</strong>Craft.<p>
<p class="muted">An opinionated framework for an API Design First approach to development.</p>
<div>
<a class="primary-btn" href="<%= @vars[:namespace] %>/rapidoc">RapiDoc</a>
<a class="primary-btn" href="<%= @vars[:namespace] %>/swaggerdoc">Swagger</a>
</div>
<br/>
<div>
<a href="https://github.com/apicraft-dev/apicraft-rails" class="github-btn" target="_blank">
⭐ Star us on GitHub
</a>
</div>
<br/>
<div>
<code class="muted">v<%= @vars[:version] %></code>
</div>
</div>
</body>
</html>
15 changes: 0 additions & 15 deletions web/views/index.html

This file was deleted.

102 changes: 102 additions & 0 deletions web/views/rapidoc.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html>
<head>
<title>APICraft - Rapidoc</title>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
<style>
body {
margin: 0;
font-family: 'Montserrat', 'Roboto', sans-serif;
background-color: #121212;
}

.select-label {
color: white;
font-weight: 400;
margin-right: 10px;
}

#api_select {
padding: 16px 16px;
color: white;
background-color: black;
border: none;
border-bottom: 1px solid #333;
border-radius: 0px;
cursor: pointer;
outline: none !important;
width: 100%;
display: none;
}

rapi-doc {
flex-grow: 1;
height: calc(100vh - 0px); /* Adjust for nav height */
width: 100%;
display: none;
}
</style>
</head>
<body>
<rapi-doc
theme="dark"
id="rapidoc_element"
header-color="#121212"
primary-color="#4C2A85"
use-path-in-nav-bar="false"
bg-color="#111"
show-header="false"
>
<div slot="nav-logo">
<img
src="assets/images/thumb.png"
height="60px"
width="60px"
/>
<span style="top: -23px; position: relative;"><strong>API</strong>Craft</span>
</div>
<select id="api_select">
</select>
</rapi-doc>
<script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
<script>
var $rapiDocElement = document.getElementById('rapidoc_element');
var $select = document.getElementById('api_select');

// List of APIs
var apis = <%=
@vars[:urls].map do |u|
{ url: u, name: u.gsub(Apicraft::Web::Router.namespace, "") }
end.to_json
%>

$rapiDocElement.setAttribute('spec-url', apis[0].url);
$rapiDocElement.setAttribute('style', "display: block;");

// Function to handle API selection change
function onSelectChange() {
var url = this.value;
$rapiDocElement.setAttribute('spec-url', url);
}

// Dynamically building the select dropdown options
apis.forEach(function(api) {
var $option = document.createElement('option');
$option.setAttribute('value', api.url);
$option.innerText = api.name;
$select.appendChild($option);
});

// Adding event listener for select dropdown change
$select.addEventListener('change', onSelectChange);
$select.setAttribute('style', "display: block;");
</script>
<style>
.header-title {
display: none !important;
}
</style>
</body>
</html>
Loading

0 comments on commit be1f601

Please sign in to comment.