Skip to content

Commit a46161b

Browse files
authored
Introduce a new api configuration property (#850)
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
1 parent 6556947 commit a46161b

35 files changed

Lines changed: 986 additions & 123 deletions

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ jobs:
5353
with:
5454
path: test/e2e/html
5555
edition: ${{ matrix.edition.name }}
56+
- name: E2E (no-api)
57+
uses: ./.github/actions/e2e
58+
with:
59+
path: test/e2e/no-api
60+
edition: ${{ matrix.edition.name }}
5661
- name: E2E (chaos)
5762
uses: ./.github/actions/e2e
5863
with:

Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ docker: docker-build
7575
$(MAKE) -C test/e2e/empty EDITION=$(EDITION)
7676
$(MAKE) -C test/e2e/headless EDITION=$(EDITION)
7777
$(MAKE) -C test/e2e/html EDITION=$(EDITION)
78+
$(MAKE) -C test/e2e/no-api EDITION=$(EDITION)
7879
$(MAKE) -C test/e2e/chaos EDITION=$(EDITION)
7980
ifeq ($(ENTERPRISE),ON)
8081
$(MAKE) -C enterprise/e2e/html EDITION=$(EDITION)

collections/self/v1/schemas/configuration/configuration.json

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616
"contents": {
1717
"$ref": "./contents.json"
1818
},
19+
"api": {
20+
"type": [ "object", "boolean" ],
21+
"additionalProperties": false
22+
},
1923
"html": {
2024
"type": [ "object", "boolean" ],
2125
"properties": {
@@ -58,5 +62,24 @@
5862
"format": "uri"
5963
}
6064
},
61-
"additionalProperties": false
65+
"additionalProperties": false,
66+
"dependentSchemas": {
67+
"api": {
68+
"if": {
69+
"properties": {
70+
"api": {
71+
"const": false
72+
}
73+
}
74+
},
75+
"then": {
76+
"required": [ "html" ],
77+
"properties": {
78+
"html": {
79+
"const": false
80+
}
81+
}
82+
}
83+
}
84+
}
6285
}

collections/self/v1/tests/configuration/configuration.test.json

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,91 @@
152152
}
153153
}
154154
}
155+
},
156+
{
157+
"description": "API as empty object with HTML enabled",
158+
"valid": true,
159+
"data": {
160+
"url": "http://localhost:8000",
161+
"api": {},
162+
"html": {
163+
"name": "Title",
164+
"description": "Description"
165+
},
166+
"contents": {
167+
"test": {
168+
"title": "A sample schema folder",
169+
"description": "For testing purposes",
170+
"github": "sourcemeta/one"
171+
}
172+
}
173+
}
174+
},
175+
{
176+
"description": "API as true with HTML enabled",
177+
"valid": true,
178+
"data": {
179+
"url": "http://localhost:8000",
180+
"api": true,
181+
"html": {
182+
"name": "Title",
183+
"description": "Description"
184+
},
185+
"contents": {
186+
"test": {
187+
"title": "A sample schema folder",
188+
"description": "For testing purposes",
189+
"github": "sourcemeta/one"
190+
}
191+
}
192+
}
193+
},
194+
{
195+
"description": "API explicitly false with HTML explicitly false",
196+
"valid": true,
197+
"data": {
198+
"url": "http://localhost:8000",
199+
"api": false,
200+
"html": false
201+
}
202+
},
203+
{
204+
"description": "API as empty object with HTML explicitly false",
205+
"valid": true,
206+
"data": {
207+
"url": "http://localhost:8000",
208+
"api": {},
209+
"html": false
210+
}
211+
},
212+
{
213+
"description": "API as true with HTML explicitly false",
214+
"valid": true,
215+
"data": {
216+
"url": "http://localhost:8000",
217+
"api": true,
218+
"html": false
219+
}
220+
},
221+
{
222+
"description": "API false with HTML as object is invalid",
223+
"valid": false,
224+
"data": {
225+
"url": "http://localhost:8000",
226+
"api": false,
227+
"html": {
228+
"name": "Title",
229+
"description": "Description"
230+
}
231+
}
232+
},
233+
{
234+
"description": "API false without HTML set is invalid",
235+
"valid": false,
236+
"data": {
237+
"url": "http://localhost:8000",
238+
"api": false
239+
}
155240
}
156241
]
157242
}

docs/api.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ hide:
77

88
!!! info
99

10-
The HTTP API and the JSON Schemas that describe it (mounted at
11-
`/self/v1/schemas`) are always available on every Sourcemeta One instance.
10+
The HTTP API is enabled by default on every Sourcemeta One instance.
11+
It can be disabled by setting `api` to `false` in the
12+
[configuration file](configuration.md#api).
1213

1314
This API has been architected with performance as a primary consideration,
1415
ensuring fast response times and efficient resource utilization across all

docs/configuration.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ structuring your instance.
6464
| `/url` | String | :red_circle: **Yes** | N/A | The absolute URL on which the instance will be served. Sourcemeta One will automatically add URI identifiers relative to this URL for every ingested schema. The absolute URL _may_ have a path component |
6565
| `/extends` | Array | No | None | One or more configuration files to extend from. See the [Extends](#extends) section for more information |
6666
| `/contents` | Object | No | None | The top-level [Collections](#collections) and [Pages](#pages) that compose the instance |
67-
| `/html` | Object or Boolean | No | `{}` | Settings for the HTML explorer. If set to `false`, the instance runs in headless mode. See the [HTML](#html) section for more details |
67+
| `/html` | Object or Boolean | No | `{}` | Settings for the HTML explorer. If set to `false`, the instance runs in headless mode. Enabling the HTML explorer implies the API must also be enabled. See the [HTML](#html) section for more details |
68+
| `/api` | Object or Boolean | No | `{}` | Controls whether the HTTP API is accessible. If set to `false`, the JSON API is disabled. Can only be set to `false` when `/html` is also set to `false` |
6869

6970
For example, a minimal configuration that mounts a single schema collection
7071
(`./schemas`) at URL `https://schemas.example.com/my-first-collection` may look

src/configuration/include/sourcemeta/one/configuration.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ struct Configuration {
4848
};
4949

5050
std::optional<HTML> html;
51+
bool api{true};
5152

5253
struct Page {
5354
std::optional<sourcemeta::core::JSON::String> title;

src/configuration/parse.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,12 @@ auto Configuration::parse(const sourcemeta::core::JSON &data,
127127
}
128128
}
129129

130+
if (data.defines("api")) {
131+
if (data.at("api").is_boolean() && !data.at("api").to_boolean()) {
132+
result.api = false;
133+
}
134+
}
135+
130136
entries_from_json(result.entries, "", data, default_base_path);
131137

132138
return result;

src/configuration/read.cc

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -170,19 +170,28 @@ auto Configuration::read(const std::filesystem::path &configuration_path,
170170
sourcemeta::core::JSON{"The next-generation JSON Schema platform"});
171171
}
172172

173-
const auto self_path{std::filesystem::weakly_canonical(
174-
collections_path / "self" / "v1" / "one.json")};
173+
if (data.is_object() && data.defines("api") && data.at("api").is_boolean() &&
174+
data.at("api").to_boolean()) {
175+
data.at("api").into_object();
176+
} else if (!data.defines("api")) {
177+
data.assign("api", sourcemeta::core::JSON::make_object());
178+
}
179+
175180
if (!data.defines("extends")) {
176181
data.assign("extends", sourcemeta::core::JSON::make_array());
177182
}
178183

179-
auto extends_copy{sourcemeta::core::JSON::make_array()};
180-
extends_copy.push_back(sourcemeta::core::JSON{self_path.string()});
181-
for (const auto &entry : data.at("extends").as_array()) {
182-
extends_copy.push_back(entry);
183-
}
184+
if (!(data.at("api").is_boolean() && !data.at("api").to_boolean())) {
185+
const auto self_path{std::filesystem::weakly_canonical(
186+
collections_path / "self" / "v1" / "one.json")};
187+
auto extends_copy{sourcemeta::core::JSON::make_array()};
188+
extends_copy.push_back(sourcemeta::core::JSON{self_path.string()});
189+
for (const auto &entry : data.at("extends").as_array()) {
190+
extends_copy.push_back(entry);
191+
}
184192

185-
data.assign("extends", std::move(extends_copy));
193+
data.assign("extends", std::move(extends_copy));
194+
}
186195

187196
const auto canonical_config{
188197
std::filesystem::weakly_canonical(configuration_path).native()};

0 commit comments

Comments
 (0)