redocly-cli
redocly-cli copied to clipboard
unevaluatedItems boolean schema error, Can't resolve $ref with component schemas
Describe the bug
Two issues here:
1. unevaluatedItems
is reporting an error Expected type 'Schema' but got 'Boolean'
related to #457 and #532, I don't see unevaluatedItems
updated similar to additionalProperties
where it can be a boolean or a schema.
- Can't resolve $ref for
Challenge
andFile
component schemas. These two referenced schemas are not resolved but they appear to be correctly defined initems
array. I tried using https://json-schema.hyperjump.io and it says my schema is valid.
To Reproduce Steps to reproduce the behavior:
- Given this
redocly.yaml
file
extends:
- recommended
- And this OpenAPI file(s)
OAS 3.1 schema
{
"openapi": "3.1.0",
"info": {
"title": "freeCodeCamp Classroom",
"version": "0.0.1",
"contact": {
"name": "Classroom Team",
"email": ""
},
"license": {
"name": "",
"url": ""
}
},
"servers": [
{
"url": "https://api.freecodecamp.org"
}
],
"security": [],
"tags": [
{
"name": "Classroom user data",
"description": ""
}
],
"paths": {
"/classroom/userData": {
"get": {
"summary": "",
"description": "",
"operationId": "getUserData",
"tags": [
"Classroom user data"
],
"parameters": [
{
"$ref": "#/components/parameters/header_accept"
}
],
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/userData"
},
"examples": {
"Classroom_User_Data": {
"$ref": "#/components/examples/userData"
}
}
}
}
},
"400": {
"$ref": "#/components/responses/400"
},
"401": {
"$ref": "#/components/responses/401"
},
"403": {
"$ref": "#/components/responses/403"
},
"404": {
"$ref": "#/components/responses/404"
},
"500": {
"$ref": "#/components/responses/500"
},
"503": {
"$ref": "#/components/responses/503"
}
}
},
"post": {
"summary": "",
"description": "",
"operationId": "queryUserData",
"tags": [
"Classroom user data"
],
"parameters": [
{
"$ref": "#/components/parameters/header_contentType"
}
],
"requestBody": {
"$ref": "#/components/requestBodies/userDataRequest"
},
"responses": {
"200": {
"description": "OK",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/userData"
},
"examples": {
"Classroom_User_Data_Request": {
"$ref": "#/components/examples/userData"
}
}
}
}
},
"400": {
"$ref": "#/components/responses/400"
},
"401": {
"$ref": "#/components/responses/401"
},
"403": {
"$ref": "#/components/responses/403"
},
"404": {
"$ref": "#/components/responses/404"
},
"500": {
"$ref": "#/components/responses/500"
},
"503": {
"$ref": "#/components/responses/503"
}
}
}
}
},
"components": {
"schemas": {
"problem_json_error": {
"type": "object",
"properties": {
"type": {
"type": "string"
},
"status": {
"type": "number",
"minimum": 200,
"maximum": 511
},
"title": {
"type": "string"
},
"detail": {
"type": "string"
},
"instance": {
"type": "string",
"format": "uri-reference"
}
}
},
"userData": {
"$id": "https://api.freecodecamp.org/classroom/userData",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"description": "list of students",
"type": "array",
"uniqueItems": true,
"items": {
"type": "object",
"properties": {
"user": {
"type": "object",
"properties": {
"id": {
"type": "string"
},
"email": {
"description": "student identifier",
"type": "string",
"format": "email"
}
}
},
"certifications": {
"description": "name of the certification (\"2022/responsive-web-design\")",
"type": "array",
"uniqueItems": true,
"minItems": 1,
"items": {
"description": "name of the certification block",
"type": "object",
"propertyNames": {
"pattern": "^[A-Za-z0-9][\/A-Za-z0-9-]*[A-Za-z]$"
},
"additionalProperties": {
"type": "object",
"unevaluatedProperties": false,
"properties": {
"blocks": {
"description": "List of the challenges/blocks inside of a certification",
"type": "array",
"uniqueItems": true,
"items": {
"type": "object",
"minProperties": 1,
"additionalProperties": {
"description": "name of the block (learn-css-...)",
"type": "object",
"properties": {
"completedChallenges": {
"type": "array",
"description": "list of challenges completed by the student inside of this block",
"uniqueItems": true,
"items": {
"$ref": "#/$defs/Challenge"
}
}
},
"required": [
"completedChallenges"
]
}
}
}
}
}
}
}
},
"required": [
"user",
"certifications"
]
},
"$defs": {
"Challenge": {
"description": "A representation of an individual challenge",
"type": "object",
"unevaluatedProperties": false,
"required": [
"id",
"challengeName",
"completedDate"
],
"properties": {
"id": {
"description": "A unique identifier of a completed course",
"type": "string",
"minLength": 1
},
"challengeName": {
"type": "string"
},
"completedDate": {
"description": "A Unix timestamp representation",
"type": "integer"
},
"files": {
"description": "A list of files pertaining to the challenge",
"type": "array",
"uniqueItems": true,
"unevaluatedItems": false,
"items": {
"$ref": "#/$defs/File"
}
}
}
},
"File": {
"description": "A representation of a file",
"type": "string",
"format": "binary"
}
}
}
},
"parameters": {
"header_accept": {
"name": "accept",
"description": "",
"in": "header",
"schema": {
"type": "string"
},
"examples": {
"accept_header": {
"summary": "A standard header indicating the accepted media type",
"value": "application/json"
}
}
},
"header_contentType": {
"name": "content-type",
"description": "",
"in": "header",
"schema": {
"type": "string"
},
"examples": {
"content-type": {
"summary": "A standard header indicating the content media type",
"value": "application/json"
}
}
}
},
"requestBodies": {
"userDataRequest": {
"description": "",
"content": {
"application/json": {
"schema": {
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "UserDataRequest",
"description": "Queries a collection of users and certifications",
"type": "object",
"unevaluatedProperties": false,
"properties": {
"users": {
"type": "array",
"uniqueItems": true,
"minItems": 1,
"prefixItems": [
{
"type": "object",
"unevaluatedProperties": false,
"properties": {
"id": {
"type": "string"
}
},
"required": [
"id"
]
}
],
"items": {
"description": "name of the certification block",
"type": "string",
"pattern": "^[A-Za-z0-9][\/A-Za-z0-9-]*[A-Za-z]$"
}
}
},
"required": [
"users"
]
},
"examples": {
"Classroom_User_Data_Request": {
"$ref": "#/components/examples/userDataRequest"
}
}
}
},
"required": true
}
},
"responses": {
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/problem_json_error"
},
"examples": {
"Bad_request_problem_json": {
"summary": "A problem+json representation of an error",
"$ref": "#/components/examples/Bad_request_problem_json"
}
}
}
}
},
"401": {
"description": "Unauthorized",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/problem_json_error"
}
}
}
},
"403": {
"description": "Forbidden",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/problem_json_error"
}
}
}
},
"404": {
"description": "Not Found",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/problem_json_error"
}
}
}
},
"500": {
"description": "Internal Server Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/problem_json_error"
}
}
}
},
"503": {
"description": "Service Unavailable",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/problem_json_error"
}
}
}
}
},
"examples": {
"userData": {
"summary": "userData from the Classroom",
"value": [
{
"user": {
"id": "",
"email": "[email protected]"
},
"certifications": [
{
"2022/responsive-web-design": {
"blocks": [
{
"learn-basic-css-by-building-a-cafe-menu": {
"completedChallenges": [
{
"id": "5f33071498eb2472b87ddee4",
"challengeName": "Step 1",
"completedDate": 1475094716730,
"files": []
},
{
"id": "5f3313e74582ad9d063e3a38",
"challengeName": "Step 2",
"completedDate": 1537207306322,
"files": []
}
]
}
}
]
}
},
{
"quality-assurance": {
"blocks": [
{
"advanced-node-and-express": {
"completedChallenges": [
{
"id": "5895f700f9fc0f352b528e63",
"challengeName": "Set up a Template Engine",
"completedDate": 98448684,
"files": []
},
{
"id": "5895f70df9fc0f352b528e6a",
"challengeName": "Create New Middleware",
"completedDate": 98448643284,
"files": []
}
]
}
},
{
"quality-assurance-and-testing-with-chai": {
"completedChallenges": [
{
"id": "587d824a367417b2b2512c46",
"challengeName": "Learn How JavaScript Assertions Work",
"completedDate": 47664591,
"files": []
}
]
}
}
]
}
}
]
}
]
},
"Bad_request_problem_json": {
"summary": "A problem+json representation of an error",
"value": {
"type": "Bad Request error",
"status": 400,
"title": "400 - Bad Request",
"detail": "You submitted a request payload with invalid JSON. Please validate your instance and resubmit"
}
},
"userDataRequest": {
"summary": "",
"value": {
"users": [
{
"id": "123456"
},
"2022/responsive-web-design",
"quality-assurance"
]
}
}
}
}
}
- Run this command with these arguments...
redocly lint --config redocly.yml fcc-classroom-userdata-openapi.json --format stylish
- See error
fcc-classroom-userdata-openapi.json:
254:53 error spec Expected type `Schema` (object) but got `boolean`
255:42 error no-unresolved-refs Can't resolve $ref
206:70 error no-unresolved-refs Can't resolve $ref
228:21 warning no-unused-components Component: "Challenge" is never used.
261:21 warning no-unused-components Component: "File" is never used.
Expected behavior
All component schemas should be referenced and unevaluatedItems: false
is a valid schema type.
Redocly Version(s)
Redocly OpenAPI - vs code v0.2.24
Node.js
Version(s)
v14.18.1
Thanks for the report @jeremyfiel!
further discussion with JSON Schema folks and they mentioned it may be an issue with resolving the base uri $id in the nested schema. It's possible ajv doesn't support this.
this seems to be a very typical use case where it's equivalent to $ref
an external schema defined as 2020-12. In this case, it's dereferenced inside the OAS definition but should resolve in the same manner as if it were externally referenced.
This is most likely an error with redocly-cli, not ajv. We don't use AJV for $ref
resolution.
We'll take a look. Thanks!
I just checked it and we indeed do not support $id in the nested schema properly.
Created a PR with potential fix here: https://github.com/Redocly/redocly-cli/pull/1286
@jeremyfiel would you be able to test the fix for your use case?
@tatomyr please reopen for the second item mentioned. @RomanHotsiy was still working on the pr for the embedded $id resolution.