- Breaking: Removed the unneeded explicit type parameters on
EnableUnknownFieldStrictMode
,EnableUnknownQueryParamStrictMode
, andLogInvalidJsonRequestBodies
- Breaking: Update Giraffe from 6.2.0 to 7.0.0. See this page for breaking changes.
- Updated FSharp.SystemTextJson from 1.2.42 to 1.3.13
- Added
SkipStandardAcceptValidation
,SkipStandardContentTypeValidation
, andSkipStandardQueryParamNameValidation
toPostCustom
, just like already exists onCustomLink
. - If a resource has a
self
link that is skipped using the query parameter specified inSkipStandardLinksQueryParamName
, theLocation
header will still be set when creating the resource.
- Added
AllowReadingBody()
to custom POST operations (after callingPostCustomAsync
). If called, it is possible to read the request body manually for this operation. This lets you for example create a POST collection operation for uploading files, and still return a valid JSON:API response. Such an endpoint is not a valid JSON:API endpoint, but can still be useful. This prevents Felicity from reading the request body, and therefore means that there must be no other POST collection operations for the same collection, since Felicity can't use the resourcetype
inb the request body to determine which POST collection operation to use. - In order to support the above, the request body is no longer eagerly read at the start of all requests. This has
necessitated the following breaking changes:
- The synchronous
PostCustomHelper.ValidateRequest
is replaced withValidateRequestAsync
andValidateRequestTask
ProhibitedRequestGetter.GetErrors
now returnsTask<_>
- The synchronous
- Updated FSharp.SystemTextJson from 1.1.34 to 1.2.42
- Updated FSharp.SystemTextJson from 1.1.23 to 1.2.34
- Updated Giraffe from 6.0.0 to 6.2.0
DELETE
resource operations now writes top-level meta just like other responses. If there is top-level meta, the response code is200
.- In custom operations, the
Responder
now has a new methodWithNoEntity()
that only writes top-levelmeta
.
- Fixed
ArgumentOutOfRangeException
when logging request body after deserialization fails andLogInvalidJsonRequestBodies
is used withmaxSize
set
- Reduced memory usage for responses with very many resources
- Updated FSharp.SystemTextJson from 1.0.7 to 1.1.23
- Added support for logging request bodies with invalid JSON using
LogInvalidJsonRequestBodies
when configuring Felicity. See the method's doc comment for more details. - Updated FSharp.SystemTextJson from 1.0.6 to 1.0.7
- Added
Filter.Field
overloads accepting parsers that returnResult<_, string>
andResult<_, string list>
- Fixed 500 Internal Server Error when primary data contains duplicate resources in GET collection and GET to-many relationship related. For these operations as well as GET to-many relationship self, now logs a warning instead (since this should not happen in client code) and returns distinct resources.
- The invalid value is now included in the error message for attribute parse errors. The value is limited to 200 characters.
- Parse error messages for attributes defined with overloads that return user-defined error messages (
e.g.
Result<_, string>
) are generally of the formAttribute 'name' got invalid value 'invalidValue': <User-defined error message>
- Fixed inadvertently returning a 500 error instead of a 400 error when a request has
null
items in a to-many relationship'sdata
array or in a resource identifier collection document's primarydata
array.
- Updated FSharp.SystemTextJson from 0.19.13 to 1.0.6. There is no change in behavior in Felicity, but note that this
comes with a breaking change if you use it in other places: When deserializing missing fields of type
option
orvoption
, an error will now be returned instead of deserializing tonull
. Either wrap such fields inSkippable
, or enable the optionIgnoreNullValues = true
. You can find more details here.
- Fix: Strict mode now correctly recognizes query parameters parsed in arity 2
RequestParserHelper.For...
methods.
- Fix: Make strict mode work with query parameters parsed using request parser's
ParseAsync
/ParseTask
- Added
SkipLink
to custom operations, which will make Felicity not add the link to the resource'slinks
object. Using this is required in order to be JSON:API compliant, but it is not enabled by default for backward compatibility reasons. - Now supports strict mode validation of query parameters in custom operations using
ValidateStrictModeQueryParams
( search the documentation for details)
- Fix: Make strict mode ignore link skip query parameters (as set up by
SkipStandardLinksQueryParamName
andSkipCustomLinksQueryParamName
)
- Added support for strict mode using
EnableUnknownFieldStrictMode
andEnableUnknownQueryParamStrictMode
when configuring Felicity. These methods will cause errors to be returned or warnings to be logged when encountering unknown fields and query parameters, respectively. - Added a new method
RequireExplicitInclude
to attributes which makes them be present in the response only if explicitly specified using sparse fieldsets - Improved errors returned when parsing values in query, header, or body:
- Parse errors for comma-separated query parameters now indicate which item had an invalid value
- Parse errors for query parameters now always have the parameter name in the message (in addition to
source.param
) - Parse errors for query parameters, headers, and resource IDs (not attributes) always have an error message that includes the invalid value
- Parse error messages for query parameters, headers, and resource IDs defined with overloads that return user-defined
error messages (e.g.
Result<_, string>
) are generally of the formQuery parameter 'name' got invalid value 'invalidValue': <User-defined error message>
- Added overloads of attribute and relationship
Get...Skip
methods without'ctx
- Added a new method
SkipRelationshipIf
to relationships that allows specifying when a relationship will be entirely omitted from the resource (i.e., no relationship links will be present). Use this together with theGet...Skip
methods. If not (as has always been the case), the links will be present, butGET
operations against them will return errors if the relationship's getter returnsSkip
.
- Errors returned for invalid JSON no longer uses the exception message, which means less implementation details are leaked (but the message may be somewhat less useful)
- The error response log message now contains the error's
source
- Custom operations now have methods for disabling the standard validation of the
Accept
andContent-Type
request headers as well as query parameter names that are illegal according to JSON:API. Consider using these if the custom link operation does not conform to JSON:API.
- Now supports tracking usage of resource fields. Search the documentation for "tracking" for details.
- The error
detail
returned when a request body contains a relationship with a resource identifier pointing to a non-existent resource now contains the resourcetype
andid
.
- Updated FSharp.SystemTextJson from 0.18.24 to 0.19.13
- Updated FSharp.SystemTextJson from 0.17.4 to 0.18.24
- Removed Hopac dependency in favor of native tasks. The primary reason is that Hopac doesn't play nice
with
System.Diagnostics.Activity
's call context flowing, breaking e.g. distributed tracing. - Removed previously deprecated methods
- Updated Giraffe from 5.0.0 to 6.0.0
- Added context transformation overloads (
ForContext
andMapSetContext
) accepting the current entity for all entity-specific operations (GET, PATCH, DELETE, custom operations, attribute/relationship setters, andSet2
). - Added
Filter
convenience methods to parse known types (similar toQuery
, but wraps the name infilter[...]
):String
,Bool
,Int
,Float
,DateTime
,DateTimeOffset
, andDateTimeOffsetAllowMissingOffset
- Fixed bug introduced in 0.18.1 where main resources that were also included in a relationship could be
null
due to a race condition in the response builder
- Added the ability to configure query parameters that, if present, will cause links to be omitted from the response.
Search the documentation for
SkipStandardLinksQueryParamName
orSkipCustomLinksQueryParamName
for details. - Performance improvements in response building, particularly in collection responses and with many shared included resources (actual improvement varies greatly by response characteristics, but tests indicate a 15-30% time reduction and 20-45% reduced memory consumption)
- Now targets only .NET 6
- Updated Hopac from 0.5.0 to 0.5.1
- Removed ignored call to
GetLinkageIfNotIncluded
for to-many relationships that returnSkip
- Added
Error.appendPointer
to append a value to an error's (current or future)source.pointer
. This can be used e.g. to specify a sub-path for object- or array-valued attributes while still relying on Felicity's automatic error pointers.
- It is now possible to use both
BaseUrl
andRelativeJsonApiRoot
together in order to place the JSON:API endpoints at a different path than the one specified in the base URL. See the documentation for details.
- Fixed startup error when using
BaseUrl
with a URL without path
verifyPathCase
now correctly handles the path/
- Added
.AllowCommas
to single filters to allow commas in the query parameter value (can be useful for filters with user input)
- Added optional argument to
UseJsonApiEndpoints
to modify endpoints, e.g. using Giraffe’sapplyBefore
andapplyAfter
.
- Improved error message if call to
IApplicationBuilder.UseJsonApiEndpoints
has no explicit type parameter, or if the context type is not registered usingIServiceCollection.AddJsonApi
Set2
andSet2SameNull
now works correctly with context mapping (define.Operation.ForContext(...)
)
- Added
define.Operation.Set2
and Addeddefine.Operation.Set2SameNull
to set two fields at the same time. Use this as a better alternative toCustomSetter
if the only thing you want is to set two fields simultaneously. - Documented important limitations of
CustomSetter
. See documentation for details.
-
Breaking: Felicity now uses Giraffe.EndpointRouting (and, by extension, ASP.NET Core’s built-in endpoint routing). To migrate:
- Remove the
jsonApi<'ctx>
handler from your Giraffe routes - Call
.AddRouting()
inConfigureServices
- Call
.UseRouting().UseJsonApiEndpoints<MyContextType>()
inConfigure
You are of course free to continue using non-Felicity Giraffe routes/handlers or any other routes like before.
- Remove the
-
Added
Routing.verifyPathCase
; see the documentation for details
- Fixed a bug where
CustomLock
would cause a503
lock timeout response to be returned instead of the correct404
response when the URL contained an invalid resource ID. - Fixed a bug where
LockOtherForModification
would cause the other resource’s creation lock to be called when the URL contained an invalid resource ID. - Fixed a bug where
LockOtherForResourceCreation
would cause the other resource’s creation lock to be called when the relationship was null.
- Fixed a bug where
LockOtherForModification
andLockOtherForCreation
would be invoked when they should not - Fixed a bug where
LockOtherForModification
andLockOtherForCreation
would invoke incorrect locks on the other resource
- Added
MapSetContext
to attributes and relationships
- Added higher-arity request parser overloads
- Split
LockOther
intoLockOtherForResourceCreation
andLockOtherForModification
to avoid overload resolution problems when only using one of the optional arguments. This also made the API more composable.
- Will now remove duplicate sort columns in
sort
query parameters. For example,sort=a,-a,-b,a,b
will be converted tosort=a,-b
before parsing. This is done because 1) duplicate sort columns will logically never influence search results (for well-behaved servers), and 2) duplicate sort columns may cause errors in some databases, e.g. SQL Server. This is a non-breaking change unless the server does something weird based on duplicate sort columns.
- Now supports checking preconditions on resource creation requests. See new POST operation methods.
- Now allows using nullable relationships in
LockOther
. Due to F# overload resolution limitations, if your resource modules are recursive, you likely need to define the relationships (whether nullable or not) above where you use them inLockOther
.
- Updated for Giraffe 5.0. As a consequence, Felicity now only targets .NET 5.
- Added missing method
define.Resource.Polymorphic().ResolveId()
, which is required when usingGetLinkageIfNotIncluded
with a polymorphic relationship.
- Relationship links are on longer present on resources with collection names but not GET resource operations
- Added possibility of supplying response-level meta by using
GetMeta
inAddJsonApi
in startup code. This lets you specify a function'ctx -> Map<obj, string>
, with the implication that'ctx
should be mutable and the meta added during the request processing.
- Fixed some internal errors being returned with the same error
id
for each occurrence
- Add
CustomResourceCreationLock
to support custom locking of resource creation operation (likePOST /articles
). This complements the existingCustomLock
, which locks everything except resource creation.
- Improved certain error messages
- Added
SetOrder
method to all fields to allow specifying the order in which fields should be set during POST collection and PATCH resource requests
- Added
AsNonNullable
andAsNonNullableOptional
to nullable attributes to require a non-null value in request parsing
- Added higher-arity request parser overloads
- Now supports taking multiple locks per resource (see documentation)
- Updated dependencies
- Fixed bug introduced in 0.14.0 where SimpleDateTimeOffset attributes were surrounded by extra double quotes during serialization
- Resource linkage may now be included by default even if the actual resource is not included
- Breaking:
SimpleDateTimeOffset
attributes now require an offset (e.g.Z
or+02:00
) when parsed. The same goes for filter query parameters for these attributes. As a side-effect,SimpleDateTimeOffset
attributes are now serialized/deserialized asstring
, notDateTimeOffset
. UseSimpleDateTimeOffsetAllowMissingOffset
to keep the old behavior where values without offset assume the server’s current offset. - Breaking:
Query.DateTimeOffset
now requires an offset when parsed. UseQuery.DateTimeOffsetAllowMissingOffset
for the old behavior where values without offset use the server’s current offset. - Update
FSharp.SystemTextJson
to v0.14.8
- Added more
LockOther
overloads
- Breaking: Simplified and improved resource locking
CustomLockOther
is removedLockOther
now simply delegates to the “parent” resource lock (recursively if needed), using the specified parameters to support POST collection operations (parent relationship) and/or all other operations (child-to-parent ID lookup)- Allow locking resources without collection names (e.g. when locking parent resources that are only accessible through relationships)
- Treat fields/params as consumed when using the one-off
GetRequired
/GetOptional
- Fix
DateTime
andDateTimeOffset
query parsing
- Enabled lookup of arbitrary types in relationship
Set
,SetAll
, andAdd
overloads accepting a resource lookup ( was previously restricted to the relationship’s related entity type, now allows lookups of e.g. simpler resource projections, or simple existence checks for the related IDs)
- Breaking: Renamed
define.Attribute.Simple
toSimpleUnsafe
and added variants for well-known types such asSimpleString
,SimpleDateTimeOffset
, etc. - Added
DateTime
andDateTimeOffset
as built-in query parser target types
- Added support for external lock mechanisms
- Fix 500 error when deserializing
null
to a reference-typed non-nullable attribute (now returns a more helpful error)
- Extended resource locking/queueing to support POST requests to create child resources. Pass in the parent relationship
to
.LockOther()
to enable this.
- Added resource locking/queueing to ensure thread safety; see the documentation for details
- Added more
AfterModifySelf
overloads to relationships
- Updated FSharp.SystemTextJson dependency
- Supported
include
query parameter for all relationshipself
URL operations
- Added
Error.setSourceParam
andError.setSourcePointer
- Fixed
AddConstraint
overload resolution
- Breaking:
RequestParserHelper.GetRequired
and.GetOptional
are renamed toGetRequiredJob
andGetOptionalJob
- Added
RequestParserHelper.GetRequiredAsync
and.GetOptionalAsync
- Base URL no longer needs to be specified in startup code
- Can add a relative JSON:API handler root path instead of the full base URL in startup code if the
jsonApi
handler is not at the root - Updated
System.Text.Json
from 4.7.1 to 4.7.2
- Fix nullable relationship request parser interpreting null data as missing relationship
- More robust workaround workaround for giraffe-fsharp/Giraffe#24
- Added workaround for giraffe-fsharp/Giraffe#24
- Enabled lookup of arbitrary types in
myRelationship.Related()
parsers (was previously restricted to the relationship’s related entity type, now allows lookups of e.g. simpler resource projections, or simple existence checks for the related IDs)
- Added additional query/header parsing overloads
- Removed
Filter.FieldAsNonNullable
to simplify field query parsing; just useFilter.Field
instead
- Fixed nullable attributes in request parser
- Improved query param helper overload resolution
- Added arity 6 overloads to request parser
- Add
.AsNonNullable
to a nullable to-one relationship’s related getter (used in request parsing) to require a non-null related resource
- Update Giraffe version
- Update and lock FSharp.SystemTextJson version
- Breaking bugfix: For operations with transformed context (
.ForContext(...)
), theResourceParserHelper
/ResourceParser
is now typed to the original context, not the mapped context, so that it actually can parse the resource’s fields (which are typed to the original context)
- Breaking: Renamed
RequestParser.Parse
toParseJob
and addedParseAsync
- Breaking: Removed the “related setter” versions of
ToManyRelationship.Remove
. These violated the JSON:API spec; they returned errors when the related resources were not found, but the spec requires a success response even if the members are already removed from the relationship. - Added
PostCustom
operation for use-cases where the strict “create entity → persist entity” workflow of the normalPost
operation doesn’t work - Fixed error for undefined resource-specific operations when the resource is not found
- Don't validate fallthrough requests
- Fixed serialization when using multiple context types
- Fixed routing when using multiple context types
- Added
Option
variants ofFilter.Field
,Query.Parsed
,Header.Parsed
, andSort.Parsed
- Huge performance improvements – Felicity overhead reduced by ~90% for very large responses, ~20% for small responses
- Add dependency on Hopac and use
Job
internally (this gave most of the performance improvements) - Add
Job
overloads as alternatives toAsync
- Add
string
overload toJsonApiConfigBuilder.BaseUrl
- Breaking: Added
Async
suffix to custom operation'sGet
,Post
,Patch
, andDelete
- Added arity 5 overloads to request parser
- Added support for sideposting (creating multiple related resources in a single POST request)
- Added ability to create custom setters in PATCH operation
- Added higher-arity
Add
overloads to request parser for functions that require more than one value parameter
- Added additional context-less
AfterUpdate
overloads to PATCH operation
- Updated dependency FSharp.SystemTextJson
- Removed own
Skippable
implementation in favor of the one from FSharp.SystemTextJson (in namespaceSystem.Text.Json.Serialization
) - Fail on startup if operations are missing required persistence functions
- Added support for optional precondition validation
- Added
define.Operation.PostBackRef
to provide access to a pre-create "parent entity" inAfterCreate
(using a relationship back-reference in the POST request)
- Added some missing attribute overloads
- Allow filtering on the resource ID
- Breaking: POST, PATCH, and DELETE operations now have a single
ModifyResponse
member instead of separate members for 202 Accepted and normal responses - Allow specifying
Async
constraints and constraint lists
- Added entity-returning overloads for PATCH's
BeforeUpdate
, DELETE'sBeforeDelete
, and relationships'BeforeModifySelf
- Breaking: Made
BeforeModifySelf
useFunc
- Added
SetNonNull
for nullable attributes and relationships that may return null, but not be set to null
- Improve some exception messages
- Return ETag for HEAD requests
- Initial release