- Operators in field expressions/filter constraints (in both the
?sortand?filterparameters) must now be prefixed with a colon. More details here: #172 (comment)
-
The format for specifying/configuring custom operators has changed slightly. Whereas operators previously defined themselves with an
isBinaryboolean field, they must now provide anarityfield, which holds a finite number (0, 1, 2, etc.) orInfinity. If you were defining custom operators, or reading the user-defined operators in a custom parser, update your code accordingly. The update is very mechanical: wherever you were readingoperator.isBinarybefore, you can replace it withoperator.arity === 2. -
Remove long-deprecated signature for
ExpressStrategy.sendResult. If you're a TS user and your code still compiles, this doesn't effect you.
- More accurate types, especially: replacing
Querywith aRunnableQueryunion type in various signatures. This may cause small breakage for Typescript users.
Adapter#doQueryhas been removed. If you were calling this manually in a query/result factory, replace those calls with the newopts.runQueryfunction, which has the same signature (and doesn't require you to know which adapter to run the query with).- The deprecated
ResourceTypeRegistry#parentTypemethod has been removed. UseResourceTypeRegistry#parentTypeNameinstead. - Constructing a
ResourceTypeRegistrywith any type descriptions that don't include adbAdapternow throws at construction time. Before, this would throw at runtime when the adapter was looked up to handle an incoming request. APIError: the deprecated constructor signature/options have been removed, as has the deprecated use of anisJSONAPIDisplayReadyproperty to indicate a non-APIError error as display-safe.
- It's now possible to specify a max page size, and default page size, for each resource type, to limit how many resources of a given type users can request at once. To do this, add a
paginationkey to your resource type descriptions, with shape:{ maxPageSize?: number; defaultPageSize?: number }. - It's now possible to override the set of supported operators on a request-by-request basis, rather than that set always being drawn from the adapter for the request's query.
-
The function signatures for
beforeSaveandbeforeRenderhave been refactored considerably. Each function now receives four arguments(it, meta, extras, superFn), whereitrefers to the object (either aResourceorResourceIdentifier) to be transformed;metarefers to aTransformMetaobject;extrasis an object full of members like the raw serverRequest, the ResourceTypeRegistry, etc; andsuperFnis a function you can call to invoke the parent type's transform. This is quite from the previous(it, frameworkReq, frameworkRes, superFn, extras, meta)signature. This change has been long-planned (though the depd module didn't provide a good way to provide a warning about it), and updating your code should be mechanical. -
Likewise, the function signature for the
superFnfunction is now(it, meta)rather than just(it). That is, you must explicitly pass along the transform meta when calling the super function.
- Query and result factories receive a partially applied version of the (resource-type-agnostic)
beforeSaveandbeforeRenderfunctions, which can be convenient. - Export more types
- MongooseAdapter: adds more information about the source of errors to the errors'
metakey.
This release:
- Adds support for
geoWithinfilters to the mongoose adapter. E.g., you can doGET /organizations?filter=(location,geoWithin,([0,0],toGeoCircle,4000)), where[0,0]is a[lng,lat]coordinate and4000is a radius in meters. - Provides more precise return types for adapter methods.
- Exports additional types that may be useful to TS users.
- Provides slightly more information about the request to query param parsers.
None of the changes should be breaking, except perhaps for Typescript users whose code doesn't match the more precise types.
With this release, all major API changes for v3 are done. Between now and the final release of v3, the plan is to:
- remove deprecated APIs;
- fix known bugs;
- update underlying dependencies dependencies (e.g., Mongoose)
- that's about it, though it's possible some other small API tweaks might happen.
The big change in this release is that Adapter methods now return results in a different format, and the Query.returning method receives the results in the new format. If you were reading/destructuring the arguments to Query.returning, you'll need to update your code accordingly. The new format is documented in src/db-adapters/AdapterInterface.ts.
- Users can now provide a custom sort parameter parser, much like the custom filter parameter parsers already supported. Additionally, these parsers are allowed to parse "sort fields", as JSON:API calls them, that represent computed values, instead of simple field references. The format for these new sort fields is
{ expression: FieldExpression, direction: "ASC" | "DESC" }, compared to the other (and still valid){ field: string, direction: "ASC" | "DESC" }format. - The
MongooseAdapternow supports ageoDistanceoperator that can be used in?sort. E.g.,GET /organizations?sort=(location,geoDistance,[lng,lat])will sort all organizations by their distance from the user-provided[lng,lat]coordinate. See tests for some caveats here.
- Because the
MongooseAdapterallows thegeoDistanceoperator in the?sortparameter, it's now possible that users of that adapter will see an{ expression, direction }sort field inQueryobjects, or in the parsed value atrequest.queryParams.sort. If you were reading/transforming that value or query objects and assuming that sort fields would always have afieldkey, then support for these new{ expression, direction }sort objects is a breaking change. - Similarly, Typescript users will find that the type for parsed sort values has been expanded to encompass the new
{ expression, direction }possibility. You may need to adjust your code accordingly. Some other types have also been tweaked.- Note: an adapter must explicitly declare, in
Adapter::supportedAdapters, which operators, if any, it supports in?sort. If an adapter doesn't declare any operators as supported there, then it doesn't have to worry about encountering{ expression, direction }sort field objects in the queries it receives, as the sort parser will mark attempts to use an operator as invalid.
- Note: an adapter must explicitly declare, in
- The API controller no longer has a static
defaultFilterParamParsermethod. Instead, this function is just a named export from the same file.
FindQuery.singularandDeleteQuery.singularhave been renamed toFindQuery.isSingularandDeleteQuery.isSingular. Likewise, the argument passed in during query construction has been renamedisSingularinstead ofsingular.
- Filtering now uses a slightly different syntax. See #160 for details.
-
If you were manually creating a Query object with filters applied, or inspecting/transforming the filters on an existing Query (including using the built-in methods like
andWhere), you should know that the format for filter constraint objects has now changed slightly. In particular, before the format was{ field: string | undefined, operator: string, value: any }; now, it's simply{ operator: string, args: any[] }. And, withinargs, references to fields are represented with anIdentifiertype, to differentiate them from strings, so you have to read theidentifier.valueto get the field name. This format is more flexible going forward (e.g, it allows more than one operand to be a field reference). The effect of these changes are that:-
When reading filter constraints, when the operator is not
andoror, you should be able to pretty mechanically replacefilterConstraint.fieldwithfilterConstraint.args[0].value, andfilterConstraint.valuewithfilterConstraint.args[1]. Likewise, when the operator isandoror, you should be able able to replaceconstraint.valuewithconstraint.args. These replacements work because, for all the built-in binary operators, you can rely onargs[0]being anIdentifier, andargs[1]being a plain value; this is because the arguments are validated immediately after the parsing process, and the built-in validation function enforces these invariants. (Custom adapters can override that if they wish.) Similarly, you can rely on the args for "and"/"or" expressions being an array of filter constraints. -
For creating filter constraint objects and adding them to/removing them from queries, you'll likely want to import the
IdentifierandFieldExpressionconstructor functions from thejson-apipackage and replace{ field: "a", value: x, operator: y }withFieldExpression(y, [Identifier("a"), x]).
-
- The FieldConstraint and FieldPredicate types have been unified into a new FieldExpression type, per the note above about a new filter constraint format.
- Error messages thrown/reported to the user for mongoose ValidationError's have been improved, but this means that you may now need to update how you test for specific errors. In particular:
-
if a required field is missing, the
typeUrion the generated APIError is now "https://jsonapi.js.org/errors/missing-required-field" instead of "https://jsonapi.js.org/errors/invalid-field-value". Thetitleis also different (to note that the value is missing, not invalid). Other properties are the same. -
if the error arises from you throwing an
APIError(e.g., in a custom validator), that error is used. Similarly, if you throw an Error marked as displaySafe, it's converted to an APIError, and that result is used. Before, a more generic error was used. -
if the error arises from an error thrown in a custom validator/setter, and that error is not an instance of
MongooseError, a generic message is used for thedetail, rather than leaking the error's raw message to user. TherawErrorproperty on the generated APIError in this case now points directly to the thrown error (not the error mongoose generated when catching it).
-
Note: betas 21 and 22 contained only small bugfixes; no breaking changes.
- Support APIError.source, use it for query parameter errors
- Replace the
ErrOrErrArr(type) export from the API controller file with anErrorOrErrorArrayexport in thesrc/types/index.tsfile. This only effects Typescript users.
- Url templates can be passed as functions to the ResourceTypeRegistry.
- Global configuration related to error handling can now be passed to the registry, including a template function for generating
aboutlinks. Accordingly,APIError.linkshas been deprecated. - APIError's have an optional
typeUrifield which can hold a URI identifying the type of the error. If present, this is serialized as thecodefield. On construction,typeUrishould be provided instead ofcodefield, which has been deprecated. - APIError's can be constructed with a
rawErroroption that holds an error object with more details. This raw error won't be serialized, but can be used downstream to further refine the APIError's message/other data.
-
Many error titles have been rewritten, and Mongo unique constraint violation errors now reach
query.catchas APIError's, not Mongo errors as before. If you or your clients were detecting specific errors, these changes may break your detection strategies. Use the newapiError.toJSON().codeto distinguish error types. Thecodefor Mongo unique constraint violation errors is: https://jsonapi.js.org/errors/unique-error -
APIError.pathshas been removed (this was non-standard). -
ResourceTypeRegistry.urlTemplatesnow returns each template as a function, rather than in its unparsed string form. The string form is available (for templates created from strings) at the function'sRFC6570Stringsymbol, which is exported by the library's index file. -
Some types related to URL templates have been renamed.
All of the changes below are very unlikely to effect you:
ResourceTypeRegistrycross-type defaults can no longer be provided as an Immutable.js Map. Use a plain js object instead.- The
ResourceTypeRegistry.behaviors()method has been removed. It wasn't being used for anything by the library. - Links are no longer parsed from request documents. If you were reading links sent by the client, please open an issue describing your use case (I'm very curious!).
- "Result factories" have been added as a new feature. See https://github.com/ethanresnick/json-api/commit/c02b9a96f6c7baeac936e426f5714239c19fc723
- The long-deprecated
ExpressStrategy.transformedAPIRequestmethod has been removed. However, query transform functionality is still available through thecustomAPIRequestmethod, and there's a very mechanical way to update: simply replace all calls tostrategy.tranformedAPIRequest(queryTransform)withstrategy.customAPIRequest({ queryTransform: queryTransform }).
beforeSave/beforeRendernow receive an additional argument providing some metadata about the resource/identifier being transformed. At the moment, this metadata is simply what section of the document ("included" or "primary") the the resource/identifier is from.- Some protected methods of the
MaybeDataWithLinksclass has been renamed. If you were subclassing this class (which you probably shouldn't, as it's really an internal detail), you may have to update your code.
- Support sending requests with already-parsed bodies into ExpressStrategy
- Other small new features and typings improvements
- Bugfixes
- The second argument to
MongooseAdapter's constructor, if provided, must now be a function that returns a type name when given a mongoose model name. Previously, the argument was a function that pluralized its input. MongooseAdapter.getModelNamehas been removed.Adapter.getModelNameis no longer a required function on the adapter interface. If you were customizing the pluralization/singularization behavior of the adapter, you may want to provide a function for the newtoModelNameargument on theDocumentationController's constructor.AdapterInterface.getModelnow takes a type name instead of a model name as its argument.MongooseAdapter.getModelhas been updated accordingly.
- Improved subtype handling (see #149)
By far the biggest breaking change in this beta is how the library handles subtypes (i.e., resource types registered with another resource type as their parent type). For details on the problem that needed to be solved and the approach taken, see #149.
If you're not using subtypes, none of these changes should effect you, unless you're using query factories (in which case you may need to do some mechanical work to set the new typePath property; see below).
Here are the most important changes:
-
In the past, a
Resourceinstance'stypefield held the name of its subtype; now, it holds the name of the parent-most type that the resource belongs to. The serialized JSONtypekey for the resource is now also the root most type, no the subytpe. The subtypes are instead stored inResource.typePath. They're then serialized to (and, on create, parsed from)resourceJSON.meta.types. -
If you're constructing a
Resourceinstance yourself (e.g., in a query factory), you must be very careful to settypePathcorrectly, as its used to run the appropriatebeforeSave/beforeRenderfunctions and potentially mongoose validation. See the Resource class for more details on its format, and the distinction between it and thetypeList. To help setting the type path, query factory functions are now passed a function (at thesetTypePathskey of their first argument) that, if passed an array ofResources will mutate them to set their type paths correctly. It can set the type path of existing resources by looking their type paths up in the adapter, or can validate + save a list of user-provided types at the type a resource is being created. -
If you were using linkage transforms, and some of your linkage was serialized to JSON with a subtype in its
typekey (rare, but it could happen if your Mongoose modelrefreferred to a child model), that linkage was previously transformed with the beforeSave/beforeRender functions from the subtype's resource description. Now, it'll be transformed only with the beforeSave/beforeRender functions of the parent type's description, and only if that type hastransformLinkage: trueset. It'll also always be serialized with the parent type's name in itstypekey, so that it points to the appropriate resource.
If you've written a custom adapter....
-
You must now implement an instance method called
getTypePaths. See MongooseAdapter for an example, and the AdapterInterface file for the signature. If you aren't supporting subtypes, you can generate the typePath for each input item by simply making a one-item array with the serialized, JSON:APItypevalue. -
If you want to support subtypes, you must update your methods that return
Resources to return the parent type intypeand the type path intypePath. Also, you must update your query methods (create/update/delete/addToRelationship/removeFromRelationship) to be aware of thetypePathkey. The library will guarantee that the resources passed in the query toadapter.createandadapter.updatehave a true type (i.e., their smallest type) ofQuery.typeor one of its subtypes, but you otherwise must validate the data yourself. Note thatQuery.typestill represents whatever type the query is scoped to (likely based onrequest.params.type), and could be a subtype. -
Finally, you must provide an instance method called
getModelName. (Before, this was required as a static method; that is no longer needed.) -
If you were subclassing MongooseAdapter, see below for the changes to it.
- Using multiple adapters simultaneously (i.e., different ones for different resource types) is no longer possible, for the moment. The fix isn't too hard, though, so open an issue if having this feature is important.
-
You must now use a mongoose version greater than 4.8.0. Versions between 4.8.x and 5 are known to work. Versions 5+ haven't been tested yet, but may work.
-
Removed
MongooseAdapter's staticgetChildTypesmethod andgetTypesAllowedInCollectioninstance method. The ResourceTypeRegistry can figure out the parent and child types based on the type descriptions provided to it, so there's no point in making adapters implement these methods. See the new methods on ResourceTypeRegistry if you need/were using this functionality. -
Removed various static
MongooseAdaptermethods (e.g.docToResource,getType,getReferencedType) from the class; they're now utility methods instead in a separate file. None of these methods were intended to be part of the class's public API (though that wasn't clearly defined), so hopefully this breakage isn't too bad. Open an issue if you were depending on these for some reason.
ResourceTypeRegistry::parentType. UseparentTypeNameinstead.
- Update Jade to Pug 2. See https://pugjs.org/api/migration-v2.html
- The library's types are exported from the main file in a way that should be more convenient for use with ESM and Typescript. Note: this shouldn't break current code to import the module, but module loading in our not-quite-ESM world is tricky, so lmk if something broke.
- The
MaybeDataWithLinksclass now has anunwrapDataWithmethod for convenience.
- The server will no longer return duplicate resources in the
includedsection. This is more compliant with the JSON:API spec, and shouldn't harm clients, but it is technically a breaking change. - The
AddToRelationshipQueryandRemoveFromRelationshipQueryclasses now take aResourceIdentifier[]as theirlinkageproperty, rather than aData<ResourceIdentifier>. If you were manually reading/setting this property in a query transform or query factory, please update your code accordingly. - Adding an
isJSONAPIDisplayReadyproperty to error objects to signal that their details can be shown to the user is deprecated; throw a proper APIError instead or use the symbol property exported from the APIError class.
-
Instead of the library constructing an initial query from the request, which you can then provide a function to transform, you can provide a function that dictates how to construct the initial query itself. (Of course, that function can use the library's built-in logic to create a query, and then transform that result, thereby recreating the same functionality as previously.) This is a subtle but important difference described in 569fa64. To use this feature, the ExpressStrategy provides a new
customAPIRequestmethod, which takes aqueryFactoryoption. See that file for details. Now thatcustomAPIRequestexists,transformedAPIRequestis deprecated. See /test/app/src/index.ts for an example of how to use the new function, and see the new implementation oftransformedAPIRequestin ExpressStategy for a sense of how to upgrade. -
The APIController, and the ExpressStrategy, now have functions for sending a JSON:API any
Resultback to the user. This is convenient if you ahve aResultthat you created manually or that otherwise came from somewhere other than executing a query inAPIController.handle. -
The public methods on the Express strategy are now bound methods, so you no-longer have to bind their
thiswhen passing them around. -
The library now prints deprecation warnings using the
depdmodule.
-
Query.returning and query.catch can now be async (returning a
Promise<Result>rather than aResultdirectly). Accordingly, if you were composing with one of those functions, you'll now have toawaitthe return value. -
Request body and query parsing now happen slightly earlier than before. Accordingly, if the user's request had multiple errors (e.g. an invalid body and an invalid method), the error returned may be different than before, because the first check that fails is the one whose error is reported.
-
The library's internal
Requestobject no longer has aprimarykey; instead it has adocumentkey which holds the whole request body parsed as aDocumentinstance (or undefined for requests with no body). This lays the ground work for supporting sideposting and other features where there's query-related data in the request document outside of the primary data. -
In the fifth argument passed to user-defined
beforeSaveandbeforeRenderfunctions, which is an object, the request and response objects generated by your HTTP framework (e.g., express, hapi, node) should now be accessed at theserverReqandserverResproperties, rather thanframeworkReqandframeworkRes. Those old names are deprecated and will be removed when v3 launches. -
ExpressStrategy.sendErrorshould now be provided with thenextfunction as an argument; not providing this will be an error when v3 is finalized. -
On
APIControllersignature ofhandlemethod has changed, and theresponseFromExternalErrormethod has been renamed toresponseFromError. These changes should only effect you if you have written a custom HTTP strategy.
- MongooseAdapter now correctly respects the
singularproperty of find and delete queries.
- On
FindQueryandDeleteQueryinstances:- The
getFiltersmethod now returns a deep clone of the filters, rather than a shallow clone, so mutating the result is safe. - The
getIdOrIdsmethod no longer exists; just get the filters with thegetFiltersmethod and filter the result as needed. - Relatedly, the
getFiltersmethod now no longer takes an argument to exclude filters that apply to theidfield; you can easily recreate this yourself. - The
matchingIdOrIdsmethod no longer forces the query to besingular: falsewhen an array of ids to match is provided, or whenundefinedis provided. This very likely won't effect you, as queries default tosingular: falseanyway unless you construct them with a single id filter or with an explicitsingular: trueconstructor argument.
- The
ResourceIdentifier's are now constructed with two arguments (type, id), rather than a single object with a type and id key. This is to be consistent with theResourceconstructor.APIError.fromErrornow sets thedetailproperty of the returned error by using thedetailproperty of the passed in Error and only falling back to thedetailsproperty ifdetailis not set. Before, it prefereddetails.Documentinstances are no longer constructed with the request URI as an argument (which was used to set the top-level self link). Instead, the top-level self link should be set like all other top-level links: by storing a self template on the value inDocument.primary.
- Linkage can be transformed on a per-type basis with an opt-in. Addresses #28. See README.
- Your
beforeRenderandbeforeSavefunctions can return undefined on requests for/inputs of a single resource to remove the resource, just like they can on multi-resource requests. If you remove the only resource from a single resource request, the result is a 200 response withdata: null. (If you need an error, you can mapnullto that with a query transform, but there's no way for the library to know the appropriate error). Addresses #105.
This beta removes support for label mappers. It also substantially reworks many of the library's underlying types. However, the type changes have mostly left the surface API unchanged and they should only effect you if:
-
You are doing query transforms that examine/modify the data in the query. This data was represented by a
ResourceorCollectionorLinkagetype instance before, but is now represented by the newDatatype. -
You are doing query transforms that change how the adapter results are put into the response, using
query.returning/query.resultsIn. The arguments to yourreturningfunction will now be different (again,Resource,Collection, andLinkageinstances will be replaced byDatainstances) and the types of theprimary/includedkeys of the document you're likely returning are now different. -
You are manually instantiating/testing for/modifying
RelationshiporLinkageinstances inbeforeSaveorbeforeRender. TheLinkagetype has been removed and theRelationshiptype substantially refactored.
See details below, and feel free to open an issue if you can't make something work.
- Removed support for label mappers. Use query transforms instead for better performance and maintainability. This resulted in the removal of
Request.allowLabelandResourceTypeRegistry.labelMappers(). - Query objects are now constructed with either an
idor anidsoption, rather than a singleidOrIdsoption.
-
A new, highly-generic type called
Datahas been introduced. It provides a uniform, monadic interface for transforming items inside it, obviating the need for the oldCollectionandLinkagetypes, which can now be represented asData<Resource>andData<ResourceIdentifier>respectively. See the comoment at the top of theData.tsfile for more details. -
Accordingly, the
CollectionandLinkagetypes have been removed, and theRelationshiptype, which previously stored link templates along with aLinkageinstance, now stores link templates along with aDatainstance. -
A new type called
ResourceSethas been introduced, which parallels the basic structure ofRelationship-- aDataplus some links -- except that the data here is aData<Resource>. This makes it possible to associate a set of links with a set ofResources (rather than each individual Resource's links), opening the door for custom top-levellinks, which wasn't previously possible. -
The result of all of the above is that various places in the code that previously could hold either a
ResourceorCollectionat runtime now always hold aData<Resource>. For example:Document.included,UpdateQuery.patch, andCreateQuery.recordsnow expect aData<Resource>Adapter.create,Adapter.update, andAdapter.deletenow return aData<Resource>; the first item in the tuple returned byAdapter.findis also aData<Resource>.
-
Meanwhile, places that always held/returned a
Collection(e.g.Document.included) now simply hold aResource[]; they don't need to/shouldn't hold aData<Resource>because having a singular one isn't possible. In this spirit, the second item in the tuple returned byAdapter.findis also now aResource[].
- The
Relationshiptype is now constructed using the staticRelationship.ofmethod rather thannew Relationship(). See source for details. Relationships must now be constructed with anowner, definining the resource (type, id) and relationship path that's the "source" of the linkage. This information is necessary to store to use as template data to render the Relationship's links. Previously, this data was missing, so the relationship's links couldn't be rendered (as top-levellinks) when the relationship was requested directly.- The link templates provided to the
Relationshipare now passed in with a slightly different format, and must be string-returning functions rather than RFC 6570 template stings. (The easiest way to satisfy this is to parse the the RFC 6570 template into a function.)
Documentinstances are now constructed with url templates provided as functions, rather than raw template strings. This shouldn't matter unless you were constructing Documents manually.Document.primary, wich previously held aResource | Collection | Relationshipnow holds aRelationship | ResourceSet. (It holds aResourceSetrather than aData<Resource>to support the possibility of top-level links, as mentioned above.)- As mentioned above,
Document.includedis now aResource[].
- The Request type is now a simple object literal rather than a class (the class ceremony wasn't buying us anything beyond extra boilerplate and a more involved construction process). If you were (for some reason) manaully constructing Request object, you'll need to update your logic.
Request.idOrIdsis now simplyRequest.id(as multiple ids were only used with label mappers).Request.needsBodyno longer exists; this wasn't actually being used by anything internally.Request.hasBodyhas also been removed; if (and only if)the request doesn't have a body,Request.bodybe undefined.Request.contentTypewill now be set if the HTTP request included a content-type header, even if there was no body. Also, when a content-type header is missingRequest.contentTypewill now be undefined rather than null.- When an Accept header is missing,
Request.acceptswill now be undefined rather than null.
- The second item in the first argument to the
FindQuery.returningcallback, which represents the included resources, is nowundefined, rather thannull, when no included resources are present.
- Q.Promise has been replaced with the standard ES6 Promise throughout the API.
- The way to filter results using the
?filterparameter has changed. The new scheme, which is documented in the README, is more concise and better integrated with the query transform system.
- The adapter now requires at least Mongoose v4.2.0, and is only tested with Mongoose 4.7.0 and up. (Previously, it used required 4.0.x).
- The adapter's methods now take a single query object, rather than a list of arguments. Unless you were calling adapter methods directly, this change shouldn't be observable.
- The
updatemethod (used on all PATCH requests) now issues afindOneAndUpdatefor each changed document, rather than trying to find the document first and then save it back. This pattern should be faster. However, it means that your mongoosesavevalidators will no longer be run; instead, thefindOneAndUpdatevalidators will be run, withthisset to be the query. By their nature, thefindOneAndUpdatevalidator functions don't know about the existing state of the doc (only the update query), so they can't enforce validation constraints that rely on reading/comparing multiple fields. (E.g., you can't validate that startDate < endDate, because the update query might only set endDate.) If you need such validations, my strong recommendation is to do them at the database level, using Mongo's new-ish document validation features. That's safer anyway, because, in the old approach, it's possible that the data could change between the read and the write, making the application-level validations give a false positive. Alternatively, I may add a "strict" update mode in the future, which could be opted-in to on a per model basis, that would increment some version field on every update. Then, it would load the document, validate it with the changes, and save the changes back but with a where clause verifying that the version hasn't changed between the read and the write. - Because of a bug in Mongoose, an update can no longer change the type of a resource (which is probably a good thing anyway -- see json-api/481 and the followup in json-api/862).
- On update, I removed the check that all documents with the targeted ids exist before trying to update any documents. This check didn't add much safety but required an extra query. Now, it's possible for some updates to succeed while others fail. (Note: the lack of true transactional updates is present throughout the library, as mongo doesn't support transactions.)
- The
addToRelationshipandremoveFromRelationshipmethods now run their validators withthisset to the update Query, rather than to null/undefined. If you were detecting whetherthiswas null/undefined, this could be a breaking change. Now, instead of checking ifthisis null, check if it isn't an instance ofMongoose.Query.
- You should now provide a Host option when initializing the strategy, for security. See example in README. If you're running your API using express 4 on a host that includes a port number you must now provide this option.
- The
HTTP/Responseclass has been removed, and replaced with object literals with a simpler format (see HTTPResponse insrc/types/index.ts) for the new structure. This should only be observable if you were subclassing theDocumentationcontroller and defining atransformTypeInfofunction that depended on the old Response structure. The argument to your function will now match the new structure. - The
Documentclass now has a different constructor signature and different class methods. This shouldn't be an issue unless you were manually constructing Document instances. See file for details.
- The type descriptions -- which have always been private -- are now stored in a different instance property. If you want to get a type description, use
registry.type(typeName). To get the list of all registered types, useregistry.typeNames().
- It's now possible to transform the query that the library builds from the request before that query is run, to support all sorts of advanced use cases. See an example here. It is also possible to transform how a query's result (whether it succeeds or fails) is mapped to the response by defining custom
returningandcatchmethods on a query object (that may want to wrap the methods already there). - The beforeSave and beforeRender transform functions are now called with an additional argument that holds an object with a
requestmember, whose value is the internal request object used by the JSON:API library, and aregistrymember, whose value is the ResourceTypeRegistry.
- This library now requires at least Node v6.
- Q.Promise's have been replaced with standard ES6 Promises in various places throughout the API.
- Response.headers.vary and Response.headers.location are not defined, rather than having a null value, if those headers aren't needed for the response.
- User-defined transform functions--namely, beforeRender and beforeSave on resource type descriptions, and transformTypeInfo on (subclasses of) the Documentation controller--are now called with slightly different arguments when the Koa adapter is in use. Previously, these functions were called with the whole Koa context object as their second-to-last argument, and undefined as their last argument. Now, the second to last argument is just Koa's request object (
ctx.request) and the last argument is Koa's response (ctx.response). This matches how the express adapter works.
- All resource descriptions must now be passed at the time of construction, as an object whose keys are the type names. Passing an array to the constructor is no longer supported.
- All setter methods have been removed. Please set all your data before initializing the Registry.
- Resource type descriptions now inherit from the descriptions of their
parentType. So if type B extends A, B will use A'sbeforeSave,beforeRender,info, etc. by default. The only exception is thatlabelMappersare not inherited. Among other things, this means that the JSON generated for sub-types now better reflects anyinfostored on the parent type's fields. (Addresses #93 and #18.) - The
ResourceTypeRegistry.types()method has been renamed toResourceTypeRegistry.typeNames() - For more details on the above, see the relevant commit.
- If you were relying on the RelationshipObject class: the class has been renamed to simply "Relationship", and its fields
selfURIandrelatedURIhave been renamed toselfURITemplateandrelatedURITemplaterespectively. - URI Templates specified on a single Relationship instance now take precedence over resource-level templates during serialization
-
Please don't use versions 2.11 and 2.12; the new features outlined below were tweaked repeatedly over those versions, and 2.13 is their (more) stable iteration. Moreover, it's just as easy to upgrade from 2.10 to 2.13 as it would be to upgrade to 2.11 or 2.12.
-
HTTP Strategies: If you are using your own HTTP strategy (including extending the built-in Express one), you must make sure that your strategy calls the Documentation controller's
handle()method with two additional arguments: the request and response objects from the framework your strategy is for (i.e. from express, koa, etc). The built-in express strategy has already been patched to support this change. -
Documentation controller: If you are using your own subclass of the Documentation controller, you must update it to be compatible with some small changes made there. In particular, a fourth constructor argument was added, and
handle()now additionally calls the newtransformTypeInfo()method. See the updated file for details.
- Very subtle changes to how the request body is parsed and stored on the request object. You almost certainly don’t need to care about these changes.
- APIController.responseFromExternalError() has a changed API
- Errors caused in the Express handler while building the Request object are now sent in a JSON API-compliant format. Before, only the status was sent or, in some cases, the app hung/crashed. See #61
- Babel's polyfills are no longer loaded globally, so, if you were relying on them, you'll need to re-include them yourself. See http://babeljs.io/docs/usage/polyfill/
- Some error objects in 4xx and 5xx responses may be different, as we now expose fewer error details by default (for security reasons). See the relevant commit for more information.
- In relationship objects,
selfandrelatedlinks now properly show up under thelinkskey. Closes #36.
- The
locationproperty on theResponseclass is now atresponse.headers.locationinstead ofresponse.location.
- Sort fields (in the
sortquery parameter) no longer need to be prefixed by a "+" to trigger ascending order, per JSON API 1.0.
-
Mongoose 4 is now required.
-
The MongooseAdapter is now at a different export path:
require("json-api").dbAdapters.MongooseAdapter. Update your references to the adapter accordingly. -
Resource type descriptions now use a
dbAdapterproperty instead ofadapter. -
The Front Controller has been replaced with an ExpressStrategy, which is exported at
require("json-api").httpStrategies.Express). The API is the same as for the old Front Controller, with the addition of some new options. -
The new payload's resource object format complies with JSON API 1.0, meaning it uses the
relationshipscontainer, rather putting relationships underlinks, and uses adatamember instead oflinkagewithin relationships. -
In auto-generated documentation’s JSON, many names were dasherized or tweaked:
-
field.kind.isArray => field.kind.is-array;
-
field.kind.targetModel => target-model;
-
field.kind.targetType => field.kind.target-type
-
field.friendlyName => field.friendly-name
-
field.validation.readOnly => field.validation.read-only;
-
field.validation.allowedHtml => field.validation.allowed-html
-
field.kind.name => field.kind.base-type;
- "Link fields" get field.kind.base-type =
"Relationship"rather than"Link" - field.validation.oneOf => field.validation.enum;
- "Link fields" get field.kind.base-type =
-