-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
Merging to release-5.7.0: [TT-13535/TT-13566] Ease up required fields in classic API schema (#6717) #6719
Merging to release-5.7.0: [TT-13535/TT-13566] Ease up required fields in classic API schema (#6717) #6719
Conversation
) ### **User description** <!-- Provide a general summary of your changes in the Title above --> * Ease up required fields on classic API definition schema * Use go:embed for classic api definition schema <!-- Describe your changes in detail --> ## Related Issue https://tyktech.atlassian.net/browse/TT-13535 https://tyktech.atlassian.net/browse/TT-13566 ## Motivation and Context <!-- Why is this change required? What problem does it solve? --> ## How This Has Been Tested <!-- Please describe in detail how you tested your changes --> <!-- Include details of your testing environment, and the tests --> <!-- you ran to see how your change affects other areas of the code, etc. --> <!-- This information is helpful for reviewers and QA. --> ## Screenshots (if appropriate) ## Types of changes <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Refactoring or add test (improvements in base code or adds test coverage to functionality) ## Checklist <!-- Go over all the following points, and put an `x` in all the boxes that apply --> <!-- If there are no documentation updates required, mark the item as checked. --> <!-- Raise up any additional concerns not covered by the checklist. --> - [ ] I ensured that the documentation is up to date - [ ] I explained why this PR updates go.mod in detail with reasoning why it's required - [ ] I would like a code coverage CI quality gate exception and have explained why ___ ### **PR Type** enhancement ___ ### **Description** - Simplified test setup in `api_definitions_test.go` by removing unnecessary `UpstreamAuth` configuration. - Enhanced schema management by using `go:embed` to load the JSON schema from an external file, improving maintainability. - Added a new `schema.json` file to store the API definition schema externally, which was previously embedded directly in the Go code. ___ ### **Changes walkthrough** 📝 <table><thead><tr><th></th><th align="left">Relevant files</th></tr></thead><tbody><tr><td><strong>Tests</strong></td><td><table> <tr> <td> <details> <summary><strong>api_definitions_test.go</strong><dd><code>Simplify test setup by removing `UpstreamAuth` configuration</code></dd></summary> <hr> apidef/api_definitions_test.go <li>Removed <code>UpstreamAuth</code> configuration from test setup.<br> <li> Simplified test cases by removing unnecessary fields.<br> </details> </td> <td><a href="https://github.com/TykTechnologies/tyk/pull/6717/files#diff-6af57c2148f42dce2ee2b93b77d65412024a802ddbd26b63f1d8bd339f4ef760">+0/-22</a> </td> </tr> </table></td></tr><tr><td><strong>Enhancement</strong></td><td><table> <tr> <td> <details> <summary><strong>schema.go</strong><dd><code>Use `go:embed` to load JSON schema from file</code> </dd></summary> <hr> apidef/schema.go <li>Removed inline JSON schema definition.<br> <li> Added <code>go:embed</code> directive to load schema from external file.<br> </details> </td> <td><a href="https://github.com/TykTechnologies/tyk/pull/6717/files#diff-f8a37bb370eb6fe20063786a5e6ea3d85a5c91d8e289f0b3e045830c4d322095">+4/-1124</a></td> </tr> <tr> <td> <details> <summary><strong>schema.json</strong><dd><code>Add external JSON schema file for API definitions</code> </dd></summary> <hr> apidef/schema.json <li>Added external JSON schema file.<br> <li> Contains API definition schema previously inlined in Go code.<br> </details> </td> <td><a href="https://github.com/TykTechnologies/tyk/pull/6717/files#diff-32c8b876e77d1639afb2d20c37b74ed9e149b72cc7de429def13d3d454e075f3">+1118/-0</a></td> </tr> </table></td></tr></tr></tbody></table> ___ > 💡 **PR-Agent usage**: Comment `/help "your question"` on any pull request to receive relevant information (cherry picked from commit 6eb5178)
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
API Changes --- prev.txt 2024-11-19 16:02:28.092814708 +0000
+++ current.txt 2024-11-19 16:02:21.520751094 +0000
@@ -97,1130 +97,6 @@
const (
ResponseProcessorResponseBodyTransform = "response_body_transform"
)
-const Schema = `{
- "type": [
- "object",
- "null"
- ],
- "$schema": "http://json-schema.org/draft-04/schema",
- "id": "http://jsonschema.net",
- "additionalProperties": false,
- "properties": {
- "is_site": {
- "type": "boolean"
- },
- "uptime_tests": {
- "type": [
- "object",
- "null"
- ]
- },
- "expire_analytics_after": {
- "type": "number"
- },
- "id": {
- "type": "string"
- },
- "org_id": {
- "type": "string"
- },
- "api_id": {
- "type": "string"
- },
- "expiration": {
- "type": "string"
- },
- "tags_disabled": {
- "type": "boolean"
- },
- "enable_ip_whitelisting": {
- "type": "boolean"
- },
- "enable_ip_blacklisting": {
- "type": "boolean"
- },
- "enable_context_vars": {
- "type": "boolean"
- },
- "strip_auth_data": {
- "type": "boolean"
- },
- "do_not_track": {
- "type": "boolean"
- },
- "enable_jwt": {
- "type": "boolean"
- },
- "use_openid": {
- "type": "boolean"
- },
- "openid_options": {
- "type": [
- "object",
- "null"
- ]
- },
- "use_standard_auth": {
- "type": "boolean"
- },
- "use_go_plugin_auth": {
- "type": "boolean"
- },
- "enable_coprocess_auth": {
- "type": "boolean"
- },
- "custom_plugin_auth_enabled": {
- "type": "boolean"
- },
- "jwt_skip_kid": {
- "type": "boolean"
- },
- "base_identity_provided_by": {
- "type": "string"
- },
- "disable_rate_limit": {
- "type": "boolean"
- },
- "disable_quota": {
- "type": "boolean"
- },
- "custom_middleware_bundle": {
- "type": "string"
- },
- "custom_middleware_bundle_disabled": {
- "type": "boolean"
- },
- "jwt_policy_field_name": {
- "type": "string"
- },
- "jwt_default_policies": {
- "type": [
- "array",
- "null"
- ]
- },
- "jwt_signing_method": {
- "type": "string"
- },
- "jwt_source": {
- "type": "string"
- },
- "jwt_identity_base_field": {
- "type": "string"
- },
- "jwt_client_base_field": {
- "type": "string"
- },
- "jwt_disable_issued_at_validation": {
- "type": "boolean"
- },
- "jwt_disable_expires_at_validation": {
- "type": "boolean"
- },
- "jwt_disable_not_before_validation": {
- "type": "boolean"
- },
- "jwt_issued_at_validation_skew": {
- "type": "number"
- },
- "jwt_expires_at_validation_skew": {
- "type": "number"
- },
- "jwt_not_before_validation_skew": {
- "type": "number"
- },
- "jwt_scope_to_policy_mapping": {
- "type": [
- "object",
- "null"
- ]
- },
- "jwt_scope_claim_name": {
- "type": "string"
- },
- "scopes": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "jwt": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "scope_claim_name": {
- "type": "string"
- },
- "scope_to_policy": {
- "type": [
- "object",
- "null"
- ]
- }
- }
- },
- "oidc": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "scope_claim_name": {
- "type": "string"
- },
- "scope_to_policy": {
- "type": [
- "object",
- "null"
- ]
- }
- }
- }
- }
- },
- "idp_client_id_mapping_disabled": {
- "type": "boolean"
- },
- "use_keyless": {
- "type": "boolean"
- },
- "use_basic_auth": {
- "type": "boolean"
- },
- "use_mutual_tls_auth": {
- "type": "boolean"
- },
- "client_certificates": {
- "type": [
- "array",
- "null"
- ]
- },
- "upstream_certificates": {
- "type": [
- "object",
- "null"
- ]
- },
- "upstream_certificates_disabled": {
- "type": "boolean"
- },
- "pinned_public_keys": {
- "type": [
- "object",
- "null"
- ]
- },
- "certificate_pinning_disabled": {
- "type": "boolean"
- },
- "allowed_ips": {
- "type": [
- "array",
- "null"
- ]
- },
- "blacklisted_ips": {
- "type": [
- "array",
- "null"
- ]
- },
- "enable_batch_request_support": {
- "type": "boolean"
- },
- "event_handlers": {
- "type": [
- "object",
- "null"
- ]
- },
- "notifications": {
- "type": [
- "object",
- "null"
- ]
- },
- "use_oauth2": {
- "type": "boolean"
- },
- "oauth_meta": {
- "type": [
- "object",
- "null"
- ]
- },
- "external_oauth": {
- "type": [
- "object",
- "null"
- ]
- },
- "cache_options": {
- "type": [
- "object",
- "null"
- ]
- },
- "tags": {
- "type": [
- "array",
- "null"
- ]
- },
- "tag_headers": {
- "type": [
- "array",
- "null"
- ]
- },
- "basic_auth": {
- "type": [
- "object",
- "null"
- ]
- },
- "CORS": {
- "type": [
- "object",
- "null"
- ]
- },
- "response_processors": {
- "type": [
- "array",
- "null"
- ]
- },
- "auth_provider": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "name": {
- "type": "string",
- "enum": [
- ""
- ]
- },
- "storage_engine": {
- "type": "string",
- "enum": [
- ""
- ]
- }
- }
- },
- "session_provider": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "name": {
- "type": "string",
- "enum": [
- ""
- ]
- },
- "storage_engine": {
- "type": "string",
- "enum": [
- ""
- ]
- }
- }
- },
- "hmac_allowed_clock_skew": {
- "type": "number"
- },
- "hmac_allowed_algorithms": {
- "type": [
- "array",
- "null"
- ]
- },
- "dont_set_quota_on_create": {
- "type": "boolean"
- },
- "custom_middleware": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "pre": {
- "type": [
- "array",
- "null"
- ]
- },
- "post": {
- "type": [
- "array",
- "null"
- ]
- }
- }
- },
- "session_lifetime_respects_key_expiration": {
- "type": "boolean"
- },
- "session_lifetime": {
- "type": "number"
- },
- "enable_detailed_recording": {
- "type": "boolean"
- },
- "enable_signature_checking": {
- "type": "boolean"
- },
- "active": {
- "type": "boolean"
- },
- "internal": {
- "type": "boolean"
- },
- "auth": {
- "type": [
- "object",
- "null"
- ],
- "id": "http://jsonschema.net/auth",
- "properties": {
- "auth_header_name": {
- "type": "string",
- "id": "http://jsonschema.net/auth/auth_header_name"
- },
- "use_certificate": {
- "type": "boolean"
- }
- }
- },
- "auth_configs": {
- "type": [
- "object",
- "null"
- ]
- },
- "definition": {
- "type": [
- "object",
- "null"
- ],
- "id": "http://jsonschema.net/definition",
- "properties": {
- "key": {
- "type": "string",
- "id": "http://jsonschema.net/definition/key"
- },
- "location": {
- "type": "string",
- "id": "http://jsonschema.net/definition/location"
- },
- "strip_path": {
- "type": "boolean",
- "id": "http://jsonschema.net/definition/location"
- }
- },
- "required": [
- "key",
- "location"
- ]
- },
- "name": {
- "type": "string",
- "id": "http://jsonschema.net/name"
- },
- "slug": {
- "type": "string",
- "pattern": "[a-zA-Z0-9]*",
- "id": "http://jsonschema.net/name"
- },
- "domain": {
- "type": "string"
- },
- "domain_disabled": {
- "type": "boolean"
- },
- "listen_port": {
- "type": "number"
- },
- "protocol": {
- "type": "string"
- },
- "enable_proxy_protocol": {
- "type": "boolean"
- },
- "certificates": {
- "type": [
- "array",
- "null"
- ]
- },
- "check_host_against_uptime_tests": {
- "type": "boolean"
- },
- "proxy": {
- "type": [
- "object",
- "null"
- ],
- "id": "http://jsonschema.net/proxy",
- "properties": {
- "target_url": {
- "type": "string",
- "id": "http://jsonschema.net/proxy/target_url"
- },
- "check_host_against_uptime_tests": {
- "type": "boolean"
- },
- "preserve_host_header": {
- "type": "boolean"
- },
- "transport": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "ssl_ciphers": {
- "type": [
- "array",
- "null"
- ]
- },
- "ssl_min_version": {
- "type": "number"
- },
- "ssl_max_version": {
- "type": "number"
- },
- "proxy_url": {
- "type": "string"
- },
- "ssl_force_common_name_check": {
- "type": "boolean"
- }
- }
- }
- },
- "required": [
- "target_url"
- ]
- },
- "hook_references": {
- "type": [
- "object",
- "null"
- ]
- },
- "version_data": {
- "type": [
- "object",
- "null"
- ],
- "id": "http://jsonschema.net/version_data",
- "properties": {
- "not_versioned": {
- "type": "boolean",
- "id": "http://jsonschema.net/version_data/not_versioned"
- },
- "default_version": {
- "type": "string",
- "id": "http://jsonschema.net/version_data/default_version"
- },
- "versions": {
- "type": [
- "object",
- "null"
- ],
- "id": "http://jsonschema.net/version_data/versions",
- "patternProperties": {
- "^[a-zA-Z0-9]+$": {
- "title": "versionInfoProperty",
- "type": [
- "object",
- "null"
- ],
- "id": "http://jsonschema.net/access_rights/versionInfoProperty",
- "properties": {
- "expires": {
- "type": "string",
- "id": "http://jsonschema.net/version_data/versions/versionInfoProperty/expires"
- },
- "name": {
- "type": "string",
- "id": "http://jsonschema.net/version_data/versions/versionInfoProperty/name"
- },
- "paths": {
- "type": [
- "object",
- "null"
- ],
- "id": "http://jsonschema.net/version_data/versions/versionInfoProperty/paths",
- "properties": {
- "black_list": {
- "type": [
- "array",
- "null"
- ],
- "id": "http://jsonschema.net/version_data/versions/versionInfoProperty/paths/black_list"
- },
- "ignored": {
- "type": [
- "array",
- "null"
- ],
- "id": "http://jsonschema.net/version_data/versions/versionInfoProperty/paths/ignored"
- },
- "white_list": {
- "type": [
- "array",
- "null"
- ],
- "id": "http://jsonschema.net/version_data/versions/versionInfoProperty/paths/white_list"
- }
- }
- }
- },
- "required": [
- "name"
- ]
- }
- }
- }
- },
- "required": [
- "not_versioned",
- "versions"
- ]
- },
- "config_data": {
- "type": [
- "object",
- "null"
- ]
- },
- "config_data_disabled": {
- "type": "boolean"
- },
- "global_rate_limit": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "rate": {
- "type": "number"
- },
- "per": {
- "type": "number"
- }
- }
- },
- "request_signing": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "is_enabled": {
- "type": "boolean"
- },
- "secret": {
- "type": "string"
- },
- "key_id": {
- "type": "string"
- },
- "algorithm": {
- "type": "string"
- }
- },
- "required": [
- "is_enabled"
- ]
- },
- "graphql": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "version": {
- "type": "string"
- },
- "execution_mode": {
- "type": "string",
- "enum": [
- "proxyOnly",
- "executionEngine",
- "subgraph",
- "supergraph",
- ""
- ]
- },
- "schema": {
- "type": "string"
- },
- "last_schema_update": {
- "type": "string",
- "format": "date-time"
- },
- "type_field_configurations": {
- "type": [
- "array",
- "null"
- ],
- "properties": {
- "type_name": {
- "type": "string"
- },
- "field_name": {
- "type": "string"
- },
- "mapping": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "disabled": {
- "type": "boolean"
- },
- "path": {
- "type": "string"
- }
- },
- "required": [
- "disabled"
- ]
- },
- "data_source": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "kind": {
- "type": "boolean"
- },
- "data_source_config": {
- "type": [
- "object",
- "null"
- ]
- }
- },
- "required": [
- "kind"
- ]
- }
- },
- "required": [
- "type_name",
- "field_name"
- ]
- },
- "engine": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "field_configs": {
- "type": [
- "array",
- "null"
- ],
- "properties": {
- "type_name": {
- "type": "string"
- },
- "field_name": {
- "type": "string"
- },
- "disable_default_mapping": {
- "type": "boolean"
- },
- "path": {
- "type": [
- "array",
- "null"
- ]
- }
- }
- },
- "data_sources": {
- "type": [
- "array",
- "null"
- ],
- "properties": {
- "kind": {
- "type": "string",
- "enum": [
- "REST",
- "GraphQL",
- ""
- ]
- },
- "name": {
- "type": "string"
- },
- "internal": {
- "type": "boolean"
- },
- "root_fields": {
- "type": [
- "array",
- "null"
- ],
- "properties": {
- "type": {
- "type": "string"
- },
- "fields": {
- "type": [
- "array",
- "null"
- ]
- }
- }
- },
- "config": {
- "type": [
- "object",
- "null"
- ]
- }
- },
- "required": [
- "kind"
- ]
- },
- "global_headers": {
- "type": [
- "array",
- "null"
- ],
- "properties": {
- "key": {
- "type": "string"
- },
- "value": {
- "type": "string"
- }
- },
- "required": [
- "key",
- "value"
- ]
- }
- }
- },
- "proxy": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "features": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "use_immutable_headers": {
- "type": "boolean"
- }
- }
- },
- "auth_headers": {
- "type": [
- "object",
- "null"
- ]
- },
- "request_headers_rewrite": {
- "type": [
- "object",
- "null"
- ],
- "additionalProperties": {
- "type": "object",
- "properties": {
- "value": {
- "type": "string"
- },
- "remove": {
- "type": "boolean"
- }
- },
- "required": [
- "value",
- "remove"
- ]
- }
- }
- }
- },
- "subgraph": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "sdl": {
- "type": "string"
- }
- }
- },
- "supergraph": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "updated_at": {
- "type": "string",
- "format": "date-time"
- },
- "disable_query_batching": {
- "type": "boolean"
- },
- "subgraphs": {
- "type": [
- "array",
- "null"
- ],
- "properties": {
- "api_id": {
- "type": "string"
- },
- "name": {
- "type": "string"
- },
- "url": {
- "type": "string"
- },
- "sdl": {
- "type": "string"
- },
- "headers": {
- "type": [
- "object",
- "null"
- ]
- }
- }
- },
- "global_headers": {
- "type": [
- "object",
- "null"
- ]
- },
- "merged_sdl": {
- "type": "string"
- }
- }
- },
- "introspection": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "disabled": {
- "type": "boolean"
- }
- }
- },
- "playground": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "path": {
- "type": "string"
- }
- },
- "required": [
- "enabled"
- ]
- }
- },
- "required": [
- "enabled"
- ]
- },
- "analytics_plugin": {
- "type": [
- "object",
- "null"
- ],
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "plugin_path": {
- "type": "string"
- },
- "func_name": {
- "type": "string"
- }
- }
- },
- "is_oas": {
- "type": "boolean"
- },
- "detailed_tracing": {
- "type": "boolean"
- },
- "upstream_auth": {
- "type": "object",
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "basic_auth": {
- "type": "object",
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "username": {
- "type": "string"
- },
- "password": {
- "type": "string"
- },
- "header_name": {
- "type": "string"
- }
- }
- },
- "oauth": {
- "type": "object",
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "client_credentials": {
- "type": "object",
- "properties": {
- "client_id": {
- "type": "string"
- },
- "client_secret": {
- "type": "string"
- },
- "token_url": {
- "type": "string"
- },
- "scopes": {
- "type": [
- "array",
- "null"
- ]
- },
- "header": {
- "type": "object",
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "name": {
- "type": "string"
- }
- },
- "required": [
- "enabled"
- ]
- },
- "extra_metadata" :{
- "type": ["array", "null"]
- }
- },
- "required": [
- "client_id",
- "client_secret",
- "token_url"
- ]
- },
- "password": {
- "type": "object",
- "properties": {
- "client_id": {
- "type": "string"
- },
- "client_secret": {
- "type": "string"
- },
- "username": {
- "type": "string"
- },
- "password": {
- "type": "string"
- },
- "token_url": {
- "type": "string"
- },
- "scopes": {
- "type": [
- "array",
- "null"
- ]
- },
- "header": {
- "type": "object",
- "properties": {
- "enabled": {
- "type": "boolean"
- },
- "name": {
- "type": "string"
- }
- },
- "required": [
- "enabled"
- ]
- },
- "extra_metadata" :{
- "type": ["array", "null"]
- }
- },
- "required": [
- "client_id",
- "token_url",
- "username",
- "password"
- ]
- }
- }
- }
- }
- }
- },
- "required": [
- "name",
- "proxy",
- "version_data"
- ]
-}
-`
VARIABLES
@@ -1260,6 +136,7 @@
var (
ErrMigrationNewVersioningEnabled = errors.New("not migratable - new versioning is already enabled")
)
+var Schema string
var Template = template.New("").Funcs(map[string]interface{}{
"jsonMarshal": func(v interface{}) (string, error) {
bs, err := json.Marshal(v) |
PR Code Suggestions ✨No code suggestions found for the PR. |
Quality Gate passedIssues Measures |
User description
[TT-13535/TT-13566] Ease up required fields in classic API schema (#6717)
User description
Related Issue
https://tyktech.atlassian.net/browse/TT-13535
https://tyktech.atlassian.net/browse/TT-13566
Motivation and Context
How This Has Been Tested
Screenshots (if appropriate)
Types of changes
functionality to change)
coverage to functionality)
Checklist
why it's required
explained why
PR Type
enhancement
Description
api_definitions_test.go
by removingunnecessary
UpstreamAuth
configuration.go:embed
to load the JSON schemafrom an external file, improving maintainability.
schema.json
file to store the API definition schemaexternally, which was previously embedded directly in the Go code.
Changes walkthrough 📝
api_definitions_test.go
Simplify test setup by removing `UpstreamAuth` configuration
apidef/api_definitions_test.go
UpstreamAuth
configuration from test setup.schema.go
Use `go:embed` to load JSON schema from file
apidef/schema.go
go:embed
directive to load schema from external file.schema.json
Add external JSON schema file for API definitions
apidef/schema.json
PR Type
Enhancement
Description
api_definitions_test.go
by removing unnecessaryUpstreamAuth
configuration.go:embed
to load the JSON schema from an external file, improving maintainability.schema.json
file to store the API definition schema externally, which was previously embedded directly in the Go code.Changes walkthrough 📝
api_definitions_test.go
Simplify test setup by removing `UpstreamAuth` configuration
apidef/api_definitions_test.go
UpstreamAuth
configuration from test setup.schema.go
Use `go:embed` to load JSON schema from file
apidef/schema.go
go:embed
directive to load schema from external file.schema.json
Add external JSON schema file for API definitions
apidef/schema.json