json-schema
json-schema copied to clipboard
Document the public API
What
The public API needs to be documented to make it clear what is intended for user access (i.e. cannot be broken without a major version bump), and what is internal to the library.
Why
So that we know what can and cannot be altered without breaking backwards-compatibility when making internal changes to the library or adding new features.
Public API (6.0.0)
As of 6.0.0
, I think that the public API of json-schema comprises the following. Anything not in this list should be able to be changed in any manner without bumping the major version number, provided it does not impact the behavior of the stuff listed here in a non-backwards-compatible manner.
Methods
Validator
-
Validator::__construct
- create a validator instance with a custom factory -
Validator::validate
- main entry point for validation -
Validator::check
- BC alias ofvalidate
(pre-5.0.0
), does not pass$value
by reference -
Validator::coerce
- BC alias ofvalidate
(pre-5.0.0
), setsCHECK_MODE_COERCE_TYPES
-
Validator::getErrors
- get array of validation errors -
Validator::numErrors
- get number of validation errors -
Validator::getErrorMask
- get the error categories -
Validator::isValid
- get overall validation status -
Validator::reset
- reset validation status
Factory
-
Factory::__construct
- create aFactory
instance with customSchemaStorage
,UriRetriever
or$checkmode
-
Factory::setConfig
- overwrite$checkMode
-
Factory::getConfig
- get$checkMode
or a filtered subset -
Factory::addConfig
- add options to$checkMode
-
Factory::removeConfig
- remove options from$checkMode
-
Factory::getSchemaStorage
- get the currentSchemaStorage
instance -
Factory::getUriRetriever
- get the currentUriRetriever
instance
SchemaStorage & SchemaStorageInterface
-
SchemaStorage::__construct
- create aSchemaStorage
instance with customUriRetriever
orUriResolver
-
SchemaStorage::addSchema
- add a schema to the storage instance by identifyng URI -
SchemaStorage::getSchema
- get a schema from the storage instance by identifying URI
UriResolver & UriResolverInterface
-
UriResolver::resolve
- resolve a URI to absolute
UriRetriever & UriRetrieverInterface
-
UriRetriever::retrieve
- retrieve & return a decoded JSON schema object
Class Constants
-
Validator::SCHEMA_MEDIA_TYPE
- official JSON schema media type -
Validator::ERROR_*
- error categories (bitmask) -
Constraint::CHECK_MODE_*
- validation options (bitmask)
Class Properties
-
Validator::$factory
- dependency injection, state & instance management
Data Formats
- The array data returned by
Validator::getErrors()
Exceptions
-
InvalidArgumentException
-
InvalidConfigException
-
InvalidSchemaException
-
InvalidSchemaMediaTypeException
-
InvalidSourceUriException
-
JsonDecodingException
-
ResourceNotFoundException
-
RuntimeException
-
UnresolvableJsonPointerException
-
UriResolverException
-
ValidationException
Please let me know if I have missed anything, or if anything in the list above needs changing. I'm fully aware that there are public methods which are not in this list - I deliberately omitted stuff I felt should not be considered part of the public API, so if you think I've omitted something that should be included, sing out!
Also, if this happens, then there will also be methods on that class which need to be considered part of the public API.
Some food for thought: http://fabien.potencier.org/pragmatism-over-theory-protected-vs-private.html
Fabien makes some good points about protected
methods also implicitly being part of the public API of a project. It's more pronounced in a project like Symfony of course, but the core points stand that for example BaseConstraint::$factory
is also part of the public API as someone might inherit their own validator from Validator
, giving them protected access to that property. That would cause breakage if it were changed in a minor/patch update.
If you wish to restrict this it could be a good idea to make the property itself private and have a protected getter.
@curry684 Unfortunately, the way this project is architected means that there will always be methods that are not part of the public API, which are declared as public or protected. No way to avoid that other than significant refactoring of the library that will break a lot of people's workflows.
From your link:
By the way, public methods does not define the public API. Sometimes, you need to declare a method as public because you need to access it from another class in your library; but that does not mean that you want your users to actually call it directly. What do you do then? Symfony and Flow3 have decided to mark the "real" public API with the @api tag. All classes, methods, and properties tagged with @api are public in the sense that we guarantee their stability over time: their name, signature, and behavior won't change for any minor version of the library. That's a strong commitment; one that I like much better than any strict enforcement done on the language level.
This is the kind of thing I'm going for here - to have a well-documented public API, and thereby avoid the confusion that may arise from relying solely on the accessibility to determine whether or not something is part of the API (which won't work for this library in its current architecture).
...for example BaseConstraint::$factory is also part of the public API as someone might inherit their own validator from Validator, giving them protected access to that property.
This is a very good point - I'll need to go through and see which properties need to available for inheritance, and which do not. I have no objection in principle to certain protected properties being considered part of the public API, but I would like to document them as such.
Although, adding a getter for Validator::$factory
does sound like an increasingly good idea, and would be consistent with how other classes are managing their own injectable dependencies. I will probably do this. Can't make it private though; that would break things.
That was my main intent with giving the food for thought: you are both working towards a new major version and documenting the API. That is the best time, if any, to evaluate all extension points that ever happened to get created, intentionally or not. In 6.0 it's perfectly acceptable to change a property from protected to private and give it a protected getter instead. Internal breakage should be zero with a proper refactoring tool.
This proposal works for me as a first phase for documentation
Closing this issue for now since there isn't any ask for it and we are very bound for time/contribution.