html_url,issue_url,id,node_id,user,user_label,created_at,updated_at,author_association,body,reactions,issue,issue_label,performed_via_github_app https://github.com/simonw/datasette/issues/1875#issuecomment-1313114283,https://api.github.com/repos/simonw/datasette/issues/1875,1313114283,IC_kwDOBm6k_c5ORIir,9599,simonw,2022-11-14T05:20:00Z,2022-11-14T05:20:00Z,OWNER,"I started a conversation about JSON error standards on Mastodon here: https://fedi.simonwillison.net/web/@simon/109338725610487457 Quite a few people pointed to this RFC independently.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1430797211,Figure out design for JSON errors (consider RFC 7807), https://github.com/simonw/datasette/issues/1875#issuecomment-1314488010,https://api.github.com/repos/simonw/datasette/issues/1875,1314488010,IC_kwDOBm6k_c5OWX7K,9599,simonw,2022-11-14T22:21:43Z,2022-11-14T22:21:43Z,OWNER,"Here's the most relevant example from the RFC spec: ``` POST /details HTTP/1.1 Host: account.example.com Accept: application/json ``` ```json { ""age"": 42.3, ""profile"": { ""color"": ""yellow"" } } ``` ``` HTTP/1.1 400 Bad Request Content-Type: application/problem+json Content-Language: en ``` ```json { ""type"": ""https://example.net/validation-error"", ""title"": ""Your request is not valid."", ""errors"": [ { ""detail"": ""must be a positive integer"", ""pointer"": ""#/age"" }, { ""detail"": ""must be 'green', 'red' or 'blue'"", ""pointer"": ""#/profile/color"" } ] } ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1430797211,Figure out design for JSON errors (consider RFC 7807), https://github.com/simonw/datasette/issues/1875#issuecomment-1314491150,https://api.github.com/repos/simonw/datasette/issues/1875,1314491150,IC_kwDOBm6k_c5OWYsO,9599,simonw,2022-11-14T22:25:20Z,2022-11-14T22:25:20Z,OWNER,"That's using JSON Pointer: https://www.rfc-editor.org/rfc/rfc6901 There's a Python library for that here https://github.com/stefankoegl/python-json-pointer/blob/master/jsonpointer.py - which looks simple and clean and well maintained and documented, but it only handles the ""what is at this pointer within this JSON object"" case - I need to generate the correct JSON pointer to explain where my error is. So I think I'll end up hand-rolling this.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1430797211,Figure out design for JSON errors (consider RFC 7807), https://github.com/simonw/datasette/issues/1875#issuecomment-1314491884,https://api.github.com/repos/simonw/datasette/issues/1875,1314491884,IC_kwDOBm6k_c5OWY3s,9599,simonw,2022-11-14T22:26:11Z,2022-11-14T22:26:54Z,OWNER,"Spec looks pretty simple: > A JSON Pointer is a Unicode string (see [RFC4627], Section 3) > containing a sequence of zero or more reference tokens, each prefixed > by a `/` (%x2F) character. > > Because the characters `~` (%x7E) and `/` (%x2F) have special > meanings in JSON Pointer, `~` needs to be encoded as `~0` and `/` > needs to be encoded as `~1` when these characters appear in a > reference token.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1430797211,Figure out design for JSON errors (consider RFC 7807), https://github.com/simonw/datasette/issues/1875#issuecomment-1314545407,https://api.github.com/repos/simonw/datasette/issues/1875,1314545407,IC_kwDOBm6k_c5OWl7_,9599,simonw,2022-11-14T23:30:34Z,2022-11-14T23:30:34Z,OWNER,TIL: https://til.simonwillison.net/json/json-pointer,"{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1430797211,Figure out design for JSON errors (consider RFC 7807), https://github.com/simonw/datasette/issues/1875#issuecomment-1314615592,https://api.github.com/repos/simonw/datasette/issues/1875,1314615592,IC_kwDOBm6k_c5OW3Eo,9599,simonw,2022-11-15T01:04:28Z,2022-11-15T01:04:28Z,OWNER,"Worth noting this bit in RFC 7807: > The fictional problem type here defines the ""errors"" extension, an > array that describes the details of each validation error. Each > member is an object containing ""detail"" to describe the issue, and > ""pointer"" to locate the problem within the request's content using a > JSON Pointer [JSON-POINTER]. So the list of `""errors""` with JSON Pointer isn't technically part of the spec, it's an imaginary extension. It fits what I need to do though, so I'm inclined to stick with it anyway.","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1430797211,Figure out design for JSON errors (consider RFC 7807), https://github.com/simonw/datasette/issues/1875#issuecomment-1314620086,https://api.github.com/repos/simonw/datasette/issues/1875,1314620086,IC_kwDOBm6k_c5OW4K2,9599,simonw,2022-11-15T01:09:56Z,2022-11-15T01:09:56Z,OWNER,"Rough initial prototype: ```diff diff --git a/datasette/views/table.py b/datasette/views/table.py index 8b987221..518ac578 100644 --- a/datasette/views/table.py +++ b/datasette/views/table.py @@ -1103,19 +1103,30 @@ class TableInsertView(BaseView): except json.JSONDecodeError as e: return _errors([""Invalid JSON: {}"".format(e)]) if not isinstance(data, dict): - return _errors([""JSON must be a dictionary""]) + return _errors([{""detail"": ""JSON must be a dictionary"", ""pointer"": ""#/""}]) keys = data.keys() # keys must contain ""row"" or ""rows"" if ""row"" not in keys and ""rows"" not in keys: return _errors(['JSON must have one or other of ""row"" or ""rows""']) rows = [] + was_single_row = False if ""row"" in keys: if ""rows"" in keys: - return _errors(['Cannot use ""row"" and ""rows"" at the same time']) + return _errors( + [ + { + ""detail"": 'Cannot use ""row"" and ""rows"" at the same time', + ""pointer"": ""#/row"", + } + ] + ) + was_single_row = True row = data[""row""] if not isinstance(row, dict): - return _errors(['""row"" must be a dictionary']) + return _errors( + [{""detail"": '""row"" must be a dictionary', ""pointer"": ""#/row""}] + ) rows = [row] data[""return""] = True else: @@ -1152,9 +1163,12 @@ class TableInsertView(BaseView): invalid_columns = set(row.keys()) - columns if invalid_columns: errors.append( - ""Row {} has invalid columns: {}"".format( - i, "", "".join(sorted(invalid_columns)) - ) + { + ""detail"": ""Invalid columns: {}"".format( + "", "".join(sorted(invalid_columns)) + ), + ""pointer"": ""#/blah/"", + } ) if errors: return _errors(errors) ```","{""total_count"": 0, ""+1"": 0, ""-1"": 0, ""laugh"": 0, ""hooray"": 0, ""confused"": 0, ""heart"": 0, ""rocket"": 0, ""eyes"": 0}",1430797211,Figure out design for JSON errors (consider RFC 7807),