apicraft-rails 0.5.0.beta1 โ 0.5.2.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +54 -16
- data/lib/apicraft/config.rb +11 -1
- data/lib/apicraft/errors.rb +1 -0
- data/lib/apicraft/middlewares/mocker.rb +32 -9
- data/lib/apicraft/version.rb +1 -1
- data/lib/apicraft/web/actions.rb +10 -27
- data/lib/apicraft/web/app.rb +2 -2
- data/lib/apicraft/web/router.rb +18 -7
- data/web/assets/images/apicraft.png +0 -0
- data/web/assets/images/apicraft_thumb.png +0 -0
- data/web/views/index.erb +83 -0
- data/web/views/rapidoc.erb +102 -0
- data/web/views/redoc.erb +25 -1
- metadata +6 -3
- data/web/views/index.html +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5411b6d7fec8f1e73a0827f8809c53212ff39f0c97d94bd5ed54825e84a81882
|
4
|
+
data.tar.gz: b4d2b5001f2aca8c32b5ac510e9b67a749e2eb5fc199ed89eaaaa42135b598df
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46cf0e60bd1d0f7551c80f118af6d8c421c8d6485252dc92a2b58d75c02f052c6c3216ac976ecb46f636fee72946c8f9662ed3af7b243575a5d716bcf5c6d40a
|
7
|
+
data.tar.gz: 5e77011472cb349e45f84131e9ef15e17b22a13576b2cb3b5f40b2311d191bede0c36bcec654932527e4e7e1c7006b3a12cd7967b8a42c9cd47865efedbbfb18
|
data/README.md
CHANGED
@@ -1,10 +1,33 @@
|
|
1
|
-
# APICraft Rails
|
1
|
+
# APICraft Rails
|
2
2
|
[![Build](https://github.com/apicraft-dev/apicraft-rails/actions/workflows/build.yml/badge.svg)](https://github.com/apicraft-dev/apicraft-rails/actions/workflows/build.yml)
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/apicraft-rails.svg?v=0.5.2.beta1)](https://badge.fury.io/rb/apicraft-rails)
|
3
4
|
|
4
5
|
๐ 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.
|
5
6
|
|
7
|
+
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.
|
8
|
+
|
9
|
+
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.
|
10
|
+
|
11
|
+
It avoids the pitfalls of the code-first methodology, where contracts are auto-generated, often leading to inconsistency and misalignment.
|
12
|
+
|
6
13
|
![APICraft Rails Logo](assets/apicraft_rails.png)
|
7
14
|
|
15
|
+
- [APICraft Rails (Beta)](#apicraft-rails-beta)
|
16
|
+
- [โจ Features](#-features)
|
17
|
+
- [๐ Upcoming Features](#-upcoming-features)
|
18
|
+
- [๐ช Works Like Magic](#-works-like-magic)
|
19
|
+
- [๐ API Design First Philosophy](#-api-design-first-philosophy)
|
20
|
+
- [๐ Installation](#-installation)
|
21
|
+
- [โ๏ธ Usage](#๏ธ-usage)
|
22
|
+
- [๐ญ API Mocking](#-api-mocking)
|
23
|
+
- [๐ฎ API Mocking (Behaviours)](#-api-mocking-behaviours)
|
24
|
+
- [๐ง API Introspection](#-api-introspection)
|
25
|
+
- [๐ API Documentation (Swagger docs and RapiDoc)](#-api-documentation-swagger-docs-and-rapidoc)
|
26
|
+
- [๐ง Configuration](#-configuration)
|
27
|
+
- [๐ค Contributing](#-contributing)
|
28
|
+
- [๐ License](#-license)
|
29
|
+
- [๐ Code of Conduct](#-code-of-conduct)
|
30
|
+
|
8
31
|
## โจ Features
|
9
32
|
- ๐งโ๐ป๏ธ **Dynamic Mock Data Generation** - Detects the specifications and instantly mounts working routes with mock responses. No extra configuration required.
|
10
33
|
|
@@ -12,11 +35,13 @@
|
|
12
35
|
|
13
36
|
- ๐ **API Introspections** - Introspect API schemas without needing to dig into the docs everytime.
|
14
37
|
|
15
|
-
- ๐บ **Documentation Out of the Box** - Documentation using `SwaggerDoc` and `
|
38
|
+
- ๐บ **Documentation Out of the Box** - Documentation using `SwaggerDoc` and `RapiDoc` both.
|
16
39
|
|
17
40
|
- ๐ **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
|
18
41
|
|
19
|
-
|
42
|
+
## ๐ Upcoming Features
|
43
|
+
- ๐ข **Request Validations** - Automatic request validations.
|
44
|
+
- ๐ **Clean & Custom Ruby DSL** - Support for a Ruby DSL alongwith the current `.json` and `.yaml` formats.
|
20
45
|
|
21
46
|
|
22
47
|
## ๐ช Works Like Magic
|
@@ -42,12 +67,12 @@ The API Design First philosophy is at the heart of APICraft Rails, and itโs a
|
|
42
67
|
By adopting an API Design First approach with APICraft Rails, you can accelerate your development process by 2-3x, delivering high-quality APIs faster and with fewer headaches.
|
43
68
|
|
44
69
|
|
45
|
-
## Installation
|
70
|
+
## ๐ Installation
|
46
71
|
|
47
72
|
Add this line to your application's Gemfile:
|
48
73
|
|
49
74
|
```ruby
|
50
|
-
gem 'apicraft-rails', '~> 0.5.
|
75
|
+
gem 'apicraft-rails', '~> 0.5.2.beta1'
|
51
76
|
```
|
52
77
|
|
53
78
|
And then execute:
|
@@ -76,7 +101,7 @@ end
|
|
76
101
|
|
77
102
|
Now every API in the specification has a functional version. For any path (from the contracts), APICraft serves a mock response when `Apicraft-Mock: true` is passed in the headers otherwise, it forwards the request to your application as usual.
|
78
103
|
|
79
|
-
## Usage
|
104
|
+
## โ๏ธ Usage
|
80
105
|
|
81
106
|
Add your specification files to the `app/contracts` directory in your Rails project. You can also configure this directory to be something else.
|
82
107
|
```
|
@@ -92,7 +117,7 @@ my_rails_app/
|
|
92
117
|
โ โ โโโ user.rb
|
93
118
|
โ โ โโโ order.rb
|
94
119
|
```
|
95
|
-
###
|
120
|
+
### ๐ญ API Mocking
|
96
121
|
**APICraft** dynamically generates mock APIs by interpreting contract specifications on the fly. You can request the mock response by passing `Apicraft-Mock: true` in the headers.
|
97
122
|
|
98
123
|
`https://yoursite.com/api/orders`
|
@@ -116,13 +141,16 @@ headers: {
|
|
116
141
|
]
|
117
142
|
```
|
118
143
|
|
144
|
+
### ๐ฎ API Mocking (Behaviours)
|
119
145
|
The above is an example of a 200 response. If you have more responses documented you can force that behaviour using `Apicraft-Response-Code` header in the mock request.
|
146
|
+
You can find a list of all the supported headers in the [configuration section](#-configuration) that would allow you to manipulate the API Behaviour.
|
120
147
|
|
121
148
|
`https://yoursite.com/api/orders`
|
122
149
|
```
|
123
150
|
headers: {
|
124
151
|
Apicraft-Response-Code: 400
|
125
152
|
Apicraft-Mock: true
|
153
|
+
Apicraft-Delay: 5
|
126
154
|
}
|
127
155
|
```
|
128
156
|
```json
|
@@ -132,7 +160,7 @@ headers: {
|
|
132
160
|
}
|
133
161
|
```
|
134
162
|
|
135
|
-
###
|
163
|
+
### ๐ง API Introspection
|
136
164
|
All APIs are can be introspected. You can do so by passing the `Apicraft-Introspection` header.
|
137
165
|
|
138
166
|
```
|
@@ -167,7 +195,7 @@ Example: `https://yoursite.com/api/orders`
|
|
167
195
|
}
|
168
196
|
}
|
169
197
|
```
|
170
|
-
###
|
198
|
+
### ๐ API Documentation (Swagger docs and RapiDoc)
|
171
199
|
|
172
200
|
Mount the documentation views in your route file.
|
173
201
|
|
@@ -182,7 +210,7 @@ end
|
|
182
210
|
|
183
211
|
You can browse API Documentation at
|
184
212
|
- `/apicraft/swaggerdoc`
|
185
|
-
- `/apicraft/
|
213
|
+
- `/apicraft/rapidoc`
|
186
214
|
|
187
215
|
Enable authentication for the `/apicraft` namespace.
|
188
216
|
|
@@ -197,8 +225,11 @@ module App
|
|
197
225
|
end
|
198
226
|
end
|
199
227
|
```
|
228
|
+
RapiDoc | SwaggerDoc
|
229
|
+
:-------------------------:|:-------------------------:
|
230
|
+
![](assets/rapidoc.png) | ![](assets/swaggerdoc.png)
|
200
231
|
|
201
|
-
## Configuration
|
232
|
+
## ๐ง Configuration
|
202
233
|
|
203
234
|
List of available configurations.
|
204
235
|
|
@@ -223,6 +254,10 @@ Apicraft.configure do |config|
|
|
223
254
|
# Defaults to true
|
224
255
|
config.strict_reference_validation = true
|
225
256
|
|
257
|
+
# When simulating delay using the mocks, the max
|
258
|
+
# delay in seconds that can be simulated
|
259
|
+
config.max_allowed_delay = 30
|
260
|
+
|
226
261
|
config.headers = {
|
227
262
|
# The name of the header used to control
|
228
263
|
# the response code of the mock
|
@@ -231,11 +266,14 @@ Apicraft.configure do |config|
|
|
231
266
|
|
232
267
|
# The name of the header to introspect the API.
|
233
268
|
# Defaults to Apicraft-Introspect
|
234
|
-
introspect: "Apicraft-Introspect"
|
269
|
+
introspect: "Apicraft-Introspect",
|
235
270
|
|
236
271
|
# The name of the header to mock the API.
|
237
272
|
# Defaults to Apicraft-Mock
|
238
|
-
mock: "Apicraft-Mock"
|
273
|
+
mock: "Apicraft-Mock",
|
274
|
+
|
275
|
+
# Delay simulation header name
|
276
|
+
delay: "Apicraft-Delay"
|
239
277
|
}
|
240
278
|
end
|
241
279
|
|
@@ -244,14 +282,14 @@ Apicraft::Web::App.use do |user, password|
|
|
244
282
|
end
|
245
283
|
```
|
246
284
|
|
247
|
-
## Contributing
|
285
|
+
## ๐ค Contributing
|
248
286
|
|
249
287
|
Bug reports and pull requests are welcome on GitHub at https://github.com/apicraft-dev/apicraft-rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/apicraft-dev/apicraft-rails/blob/main/CODE_OF_CONDUCT.md).
|
250
288
|
|
251
|
-
## License
|
289
|
+
## ๐ License
|
252
290
|
|
253
291
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
254
292
|
|
255
|
-
## Code of Conduct
|
293
|
+
## ๐ Code of Conduct
|
256
294
|
|
257
295
|
Everyone interacting in the Apicraft project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/apicraft/blob/main/CODE_OF_CONDUCT.md).
|
data/lib/apicraft/config.rb
CHANGED
@@ -13,12 +13,14 @@ module Apicraft
|
|
13
13
|
response_code: "Apicraft-Response-Code",
|
14
14
|
introspect: "Apicraft-Introspect",
|
15
15
|
mock: "Apicraft-Mock",
|
16
|
+
delay: "Apicraft-Delay",
|
16
17
|
content_type: "Content-Type"
|
17
18
|
},
|
18
19
|
mocks: true,
|
19
20
|
introspection: true,
|
20
21
|
strict_reference_validation: true,
|
21
|
-
request_validations: true
|
22
|
+
request_validations: true,
|
23
|
+
max_allowed_delay: 30
|
22
24
|
}.with_indifferent_access
|
23
25
|
|
24
26
|
def initialize(opts = {})
|
@@ -47,6 +49,10 @@ module Apicraft
|
|
47
49
|
@opts[:introspection]
|
48
50
|
end
|
49
51
|
|
52
|
+
def max_allowed_delay
|
53
|
+
@opts[:max_allowed_delay]
|
54
|
+
end
|
55
|
+
|
50
56
|
def contracts_path=(contracts_path)
|
51
57
|
@opts[:contracts_path] = contracts_path
|
52
58
|
end
|
@@ -67,6 +73,10 @@ module Apicraft
|
|
67
73
|
@opts[:request_validations] = enabled
|
68
74
|
end
|
69
75
|
|
76
|
+
def max_allowed_delay=(enabled)
|
77
|
+
@opts[:max_allowed_delay] = enabled
|
78
|
+
end
|
79
|
+
|
70
80
|
def headers=(headers)
|
71
81
|
@opts[:headers] = @opts[:headers].merge(
|
72
82
|
headers.with_indifferent_access
|
data/lib/apicraft/errors.rb
CHANGED
@@ -15,15 +15,9 @@ module Apicraft
|
|
15
15
|
request = ActionDispatch::Request.new(env)
|
16
16
|
return @app.call(env) unless mock?(request)
|
17
17
|
|
18
|
-
|
19
|
-
|
20
|
-
)
|
21
|
-
raise Errors::InvalidContract if contract.blank?
|
22
|
-
|
23
|
-
operation = contract.operation(
|
24
|
-
request.method, request.path_info
|
25
|
-
)
|
26
|
-
raise Errors::InvalidOperation if operation.blank?
|
18
|
+
use_delay!(request)
|
19
|
+
contract = find_contract!(request)
|
20
|
+
operation = find_operation!(contract, request)
|
27
21
|
|
28
22
|
code = request.headers[config.headers[:response_code]] || "200"
|
29
23
|
response = operation.response_for(code.to_s)
|
@@ -64,6 +58,35 @@ module Apicraft
|
|
64
58
|
def mock?(request)
|
65
59
|
request.headers[config.headers[:mock]].present?
|
66
60
|
end
|
61
|
+
|
62
|
+
def find_contract!(request)
|
63
|
+
contract = Apicraft::Openapi::Contract.find_by_operation(
|
64
|
+
request.method, request.path_info
|
65
|
+
)
|
66
|
+
raise Errors::InvalidContract if contract.blank?
|
67
|
+
|
68
|
+
contract
|
69
|
+
end
|
70
|
+
|
71
|
+
def find_operation!(contract, request)
|
72
|
+
operation = contract.operation(
|
73
|
+
request.method, request.path_info
|
74
|
+
)
|
75
|
+
raise Errors::InvalidOperation if operation.blank?
|
76
|
+
|
77
|
+
operation
|
78
|
+
end
|
79
|
+
|
80
|
+
def use_delay!(request)
|
81
|
+
request_delay = delay(request)
|
82
|
+
raise Errors::DelayTooHigh if request_delay > config.max_allowed_delay
|
83
|
+
|
84
|
+
sleep(request_delay)
|
85
|
+
end
|
86
|
+
|
87
|
+
def delay(request)
|
88
|
+
request.headers[config.headers[:delay]].to_i
|
89
|
+
end
|
67
90
|
end
|
68
91
|
end
|
69
92
|
end
|
data/lib/apicraft/version.rb
CHANGED
data/lib/apicraft/web/actions.rb
CHANGED
@@ -5,16 +5,11 @@ module Apicraft
|
|
5
5
|
# Web actions to be handled from
|
6
6
|
# the rack app.
|
7
7
|
module Actions
|
8
|
-
def self.
|
9
|
-
[
|
10
|
-
File.read(view_path),
|
11
|
-
"text/html"
|
12
|
-
]
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.swaggerdoc(view_path)
|
8
|
+
def self.render_erb(view_path)
|
16
9
|
@vars = {
|
17
|
-
urls: Router.contract_urls
|
10
|
+
urls: Router.contract_urls,
|
11
|
+
namespace: Router.namespace,
|
12
|
+
version: Apicraft::VERSION
|
18
13
|
}
|
19
14
|
|
20
15
|
[
|
@@ -25,16 +20,10 @@ module Apicraft
|
|
25
20
|
]
|
26
21
|
end
|
27
22
|
|
28
|
-
def self.
|
29
|
-
@vars = {
|
30
|
-
urls: Router.contract_urls
|
31
|
-
}
|
32
|
-
|
23
|
+
def self.images(view_path)
|
33
24
|
[
|
34
|
-
|
35
|
-
|
36
|
-
).result(binding),
|
37
|
-
"text/html"
|
25
|
+
File.read(view_path),
|
26
|
+
mime_type(view_path)
|
38
27
|
]
|
39
28
|
end
|
40
29
|
|
@@ -45,15 +34,9 @@ module Apicraft
|
|
45
34
|
]
|
46
35
|
end
|
47
36
|
|
48
|
-
def self.
|
49
|
-
|
50
|
-
|
51
|
-
method, view_path
|
52
|
-
)&.operation(
|
53
|
-
method, view_path
|
54
|
-
)&.raw_schema&.to_json,
|
55
|
-
"application/json"
|
56
|
-
]
|
37
|
+
def self.mime_type(view_path)
|
38
|
+
ext = File.extname(view_path)
|
39
|
+
Rack::Mime.mime_type(ext)
|
57
40
|
end
|
58
41
|
end
|
59
42
|
end
|
data/lib/apicraft/web/app.rb
CHANGED
@@ -13,10 +13,10 @@ module Apicraft
|
|
13
13
|
Router.namespace = env["SCRIPT_NAME"]
|
14
14
|
path = uri.split(
|
15
15
|
Router.namespace
|
16
|
-
)[-1]
|
16
|
+
)[-1] || "/"
|
17
17
|
|
18
18
|
content, content_type = Router.load_response!(
|
19
|
-
method, path
|
19
|
+
method, path
|
20
20
|
)
|
21
21
|
|
22
22
|
raise Errors::RouteNotFound if content.nil?
|
data/lib/apicraft/web/router.rb
CHANGED
@@ -7,20 +7,33 @@ module Apicraft
|
|
7
7
|
WEB_ROOT = File.expand_path(
|
8
8
|
"#{File.dirname(__FILE__)}/../../../web"
|
9
9
|
)
|
10
|
+
IMAGES_DIR = "#{WEB_ROOT}/assets/images"
|
10
11
|
|
11
12
|
def self.routes
|
12
13
|
@routes ||= {
|
13
14
|
"/": {
|
14
|
-
action: :
|
15
|
-
view_path: "#{WEB_ROOT}/views/index.
|
15
|
+
action: :render_erb,
|
16
|
+
view_path: "#{WEB_ROOT}/views/index.erb"
|
16
17
|
},
|
17
18
|
"/swaggerdoc": {
|
18
|
-
action: :
|
19
|
+
action: :render_erb,
|
19
20
|
view_path: "#{WEB_ROOT}/views/swaggerdoc.erb"
|
20
21
|
},
|
21
22
|
"/redoc": {
|
22
|
-
action: :
|
23
|
+
action: :render_erb,
|
23
24
|
view_path: "#{WEB_ROOT}/views/redoc.erb"
|
25
|
+
},
|
26
|
+
"/rapidoc": {
|
27
|
+
action: :render_erb,
|
28
|
+
view_path: "#{WEB_ROOT}/views/rapidoc.erb"
|
29
|
+
},
|
30
|
+
"/assets/images/thumb.png": {
|
31
|
+
action: :images,
|
32
|
+
view_path: "#{IMAGES_DIR}/apicraft_thumb.png"
|
33
|
+
},
|
34
|
+
"/assets/images/logo.png": {
|
35
|
+
action: :images,
|
36
|
+
view_path: "#{IMAGES_DIR}/apicraft.png"
|
24
37
|
}
|
25
38
|
}.with_indifferent_access
|
26
39
|
end
|
@@ -32,9 +45,7 @@ module Apicraft
|
|
32
45
|
}
|
33
46
|
end
|
34
47
|
|
35
|
-
def self.load_response!(
|
36
|
-
return Actions.introspect(method, path) unless routes[path].present?
|
37
|
-
|
48
|
+
def self.load_response!(_method, path)
|
38
49
|
Actions.send(
|
39
50
|
routes[path][:action],
|
40
51
|
routes[path][:view_path]
|
Binary file
|
Binary file
|
data/web/views/index.erb
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>APICraft</title>
|
5
|
+
<meta charset="utf-8"/>
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
8
|
+
<style>
|
9
|
+
body {
|
10
|
+
margin: 0;
|
11
|
+
padding-top: 40px;
|
12
|
+
font-family: 'Montserrat', 'Roboto', sans-serif;
|
13
|
+
background-color: #121212;
|
14
|
+
position: relative;
|
15
|
+
}
|
16
|
+
#container {
|
17
|
+
margin-top: 60px;
|
18
|
+
text-align: center;
|
19
|
+
max-width: 550px;
|
20
|
+
margin-left: auto;
|
21
|
+
margin-right: auto;
|
22
|
+
color: white;
|
23
|
+
}
|
24
|
+
.muted {
|
25
|
+
opacity: 0.5;
|
26
|
+
}
|
27
|
+
.primary-btn {
|
28
|
+
background-color: #4C2A85;
|
29
|
+
color: white;
|
30
|
+
padding: 10px 20px;
|
31
|
+
text-decoration: none;
|
32
|
+
border-radius: 5px;
|
33
|
+
font-size: 16px;
|
34
|
+
display: inline-block;
|
35
|
+
cursor: pointer;
|
36
|
+
transition: background-color 0.3s ease;
|
37
|
+
}
|
38
|
+
|
39
|
+
.primary-btn:hover {
|
40
|
+
background-color: #3A2064;
|
41
|
+
}
|
42
|
+
|
43
|
+
.github-btn {
|
44
|
+
background-color: white;
|
45
|
+
color: #4C2A85;
|
46
|
+
padding: 5px 10px;
|
47
|
+
text-decoration: none;
|
48
|
+
border-radius: 5px;
|
49
|
+
font-size: 12px;
|
50
|
+
display: inline-block;
|
51
|
+
border: 2px solid #4C2A85;
|
52
|
+
cursor: pointer;
|
53
|
+
transition: background-color 0.3s ease, color 0.3s ease, box-shadow 0.3s ease;
|
54
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
55
|
+
}
|
56
|
+
|
57
|
+
.github-btn:hover {
|
58
|
+
box-shadow: 0 6px 8px rgba(0, 0, 0, 0.15);
|
59
|
+
}
|
60
|
+
</style>
|
61
|
+
</head>
|
62
|
+
<body>
|
63
|
+
<div id="container">
|
64
|
+
<img src="<%= @vars[:namespace] %>/assets/images/logo.png" height="120" width="120"/>
|
65
|
+
<p>Welcome to <strong>API</strong>Craft.<p>
|
66
|
+
<p class="muted">An opinionated framework for an API Design First approach to development.</p>
|
67
|
+
<div>
|
68
|
+
<a class="primary-btn" href="<%= @vars[:namespace] %>/rapidoc">RapiDoc</a>
|
69
|
+
<a class="primary-btn" href="<%= @vars[:namespace] %>/swaggerdoc">Swagger</a>
|
70
|
+
</div>
|
71
|
+
<br/>
|
72
|
+
<div>
|
73
|
+
<a href="https://github.com/apicraft-dev/apicraft-rails" class="github-btn" target="_blank">
|
74
|
+
โญ Star us on GitHub
|
75
|
+
</a>
|
76
|
+
</div>
|
77
|
+
<br/>
|
78
|
+
<div>
|
79
|
+
<code class="muted">v<%= @vars[:version] %></code>
|
80
|
+
</div>
|
81
|
+
</div>
|
82
|
+
</body>
|
83
|
+
</html>
|
@@ -0,0 +1,102 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>APICraft - Rapidoc</title>
|
5
|
+
<meta charset="utf-8"/>
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
8
|
+
<style>
|
9
|
+
body {
|
10
|
+
margin: 0;
|
11
|
+
font-family: 'Montserrat', 'Roboto', sans-serif;
|
12
|
+
background-color: #121212;
|
13
|
+
}
|
14
|
+
|
15
|
+
.select-label {
|
16
|
+
color: white;
|
17
|
+
font-weight: 400;
|
18
|
+
margin-right: 10px;
|
19
|
+
}
|
20
|
+
|
21
|
+
#api_select {
|
22
|
+
padding: 16px 16px;
|
23
|
+
color: white;
|
24
|
+
background-color: black;
|
25
|
+
border: none;
|
26
|
+
border-bottom: 1px solid #333;
|
27
|
+
border-radius: 0px;
|
28
|
+
cursor: pointer;
|
29
|
+
outline: none !important;
|
30
|
+
width: 100%;
|
31
|
+
display: none;
|
32
|
+
}
|
33
|
+
|
34
|
+
rapi-doc {
|
35
|
+
flex-grow: 1;
|
36
|
+
height: calc(100vh - 0px); /* Adjust for nav height */
|
37
|
+
width: 100%;
|
38
|
+
display: none;
|
39
|
+
}
|
40
|
+
</style>
|
41
|
+
</head>
|
42
|
+
<body>
|
43
|
+
<rapi-doc
|
44
|
+
theme="dark"
|
45
|
+
id="rapidoc_element"
|
46
|
+
header-color="#121212"
|
47
|
+
primary-color="#4C2A85"
|
48
|
+
use-path-in-nav-bar="false"
|
49
|
+
bg-color="#111"
|
50
|
+
show-header="false"
|
51
|
+
>
|
52
|
+
<div slot="nav-logo">
|
53
|
+
<img
|
54
|
+
src="assets/images/thumb.png"
|
55
|
+
height="60px"
|
56
|
+
width="60px"
|
57
|
+
/>
|
58
|
+
<span style="top: -23px; position: relative;"><strong>API</strong>Craft</span>
|
59
|
+
</div>
|
60
|
+
<select id="api_select">
|
61
|
+
</select>
|
62
|
+
</rapi-doc>
|
63
|
+
<script type="module" src="https://unpkg.com/rapidoc/dist/rapidoc-min.js"></script>
|
64
|
+
<script>
|
65
|
+
var $rapiDocElement = document.getElementById('rapidoc_element');
|
66
|
+
var $select = document.getElementById('api_select');
|
67
|
+
|
68
|
+
// List of APIs
|
69
|
+
var apis = <%=
|
70
|
+
@vars[:urls].map do |u|
|
71
|
+
{ url: u, name: u.gsub(Apicraft::Web::Router.namespace, "") }
|
72
|
+
end.to_json
|
73
|
+
%>
|
74
|
+
|
75
|
+
$rapiDocElement.setAttribute('spec-url', apis[0].url);
|
76
|
+
$rapiDocElement.setAttribute('style', "display: block;");
|
77
|
+
|
78
|
+
// Function to handle API selection change
|
79
|
+
function onSelectChange() {
|
80
|
+
var url = this.value;
|
81
|
+
$rapiDocElement.setAttribute('spec-url', url);
|
82
|
+
}
|
83
|
+
|
84
|
+
// Dynamically building the select dropdown options
|
85
|
+
apis.forEach(function(api) {
|
86
|
+
var $option = document.createElement('option');
|
87
|
+
$option.setAttribute('value', api.url);
|
88
|
+
$option.innerText = api.name;
|
89
|
+
$select.appendChild($option);
|
90
|
+
});
|
91
|
+
|
92
|
+
// Adding event listener for select dropdown change
|
93
|
+
$select.addEventListener('change', onSelectChange);
|
94
|
+
$select.setAttribute('style', "display: block;");
|
95
|
+
</script>
|
96
|
+
<style>
|
97
|
+
.header-title {
|
98
|
+
display: none !important;
|
99
|
+
}
|
100
|
+
</style>
|
101
|
+
</body>
|
102
|
+
</html>
|
data/web/views/redoc.erb
CHANGED
@@ -60,8 +60,32 @@
|
|
60
60
|
end.to_json
|
61
61
|
%>
|
62
62
|
|
63
|
+
const customTheme = {
|
64
|
+
colors: {
|
65
|
+
primary: {
|
66
|
+
main: '#4CAF50', // Set the primary color to #4CAF50
|
67
|
+
},
|
68
|
+
text: {
|
69
|
+
primary: '#ffffff',
|
70
|
+
secondary: '#b0b0b0',
|
71
|
+
},
|
72
|
+
background: {
|
73
|
+
primary: '#1a1a1a', // Set the background color to #1a1a1a
|
74
|
+
secondary: '#222222',
|
75
|
+
},
|
76
|
+
borders: '#4CAF50', // Border color for primary sections
|
77
|
+
},
|
78
|
+
typography: {
|
79
|
+
fontSize: '16px',
|
80
|
+
fontFamily: '"Montserrat", "Roboto", sans-serif',
|
81
|
+
},
|
82
|
+
sidebar: {
|
83
|
+
backgroundColor: '#2b2b2b',
|
84
|
+
},
|
85
|
+
};
|
86
|
+
|
63
87
|
// Initially render first API
|
64
|
-
Redoc.init(apis[0].url);
|
88
|
+
Redoc.init(apis[0].url, { theme: null });
|
65
89
|
|
66
90
|
// Function to handle API selection change
|
67
91
|
function onSelectChange() {
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: apicraft-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.2.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abhishek Sarkar
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-09-
|
11
|
+
date: 2024-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -154,7 +154,10 @@ files:
|
|
154
154
|
- lib/apicraft/web/actions.rb
|
155
155
|
- lib/apicraft/web/app.rb
|
156
156
|
- lib/apicraft/web/router.rb
|
157
|
-
- web/
|
157
|
+
- web/assets/images/apicraft.png
|
158
|
+
- web/assets/images/apicraft_thumb.png
|
159
|
+
- web/views/index.erb
|
160
|
+
- web/views/rapidoc.erb
|
158
161
|
- web/views/redoc.erb
|
159
162
|
- web/views/swaggerdoc.erb
|
160
163
|
homepage: https://github.com/apicraft-dev/apicraft-rails
|
data/web/views/index.html
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
<!DOCTYPE html>
|
2
|
-
<html>
|
3
|
-
<head>
|
4
|
-
<title>APICraft</title>
|
5
|
-
<meta charset="utf-8"/>
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
-
<link href="https://fonts.googleapis.com/css?family=Montserrat:300,400,700|Roboto:300,400,700" rel="stylesheet">
|
8
|
-
<style>
|
9
|
-
</style>
|
10
|
-
</head>
|
11
|
-
<body>
|
12
|
-
<nav>
|
13
|
-
</nav>
|
14
|
-
</body>
|
15
|
-
</html>
|