As a developer, I want to be able to create a new Wikidata item in it's entirety
`POST rest.php/wikibase/v0/entities/items
`
```
{
"item": {
"labels": {}, [label or description in one language code is mandatory]
"descriptions": {},
"aliases": {},
"sitelinks": {}
"statements": {}
},
"comment": ... (optional)
"tags": [ ... ] (optional)
"bot": false (optional)
}
```
**Acceptance criteria**
- At least adding a label or a description in one language is mandatory
- 201 response code on success and location header in the successful creation response
- Ignore HTTP conditional request headers
- Statement errors can be handled similar to those in `POST /entities/items/{item_id}/statements`
- Ignore id and type if it's not the current ID and not "item" respectively
- ETag, last-modified and location (URI of the newly created item) as response headers.
- Handle user authentication/authorization like in `POST /entities/items/{item_id}/statements`
- Client can provide additional edit metadata: mediawiki tags, edit summary text to append to the automated summary, and a bot edit flag, like in POST /entities/items/{item_id}/statements
**Error cases to consider**
<table>
<tr>
<th>
</th>
<th>HTTP response code</th>
<th>response payload</th>
</tr>
<tr>
<td>Invalid edit tag</td>
<td>400</td>
<td>
`"code": "invalid-edit-tag"`
`"message": "Invalid MediaWiki tag: {tag}"`
</td>
</tr>
<tr>
<td>Comment too long</td>
<td>400</td>
<td>
`"code": "comment-too-long"`
`"message": "Comment must not be longer than {limit} characters"`
</td>
</tr>
<tr>
<td>Invalid data in field</td>
<td>400</td>
<td>
`"code": "item-data-invalid-field"`
`"message": "Invalid input for '{field}'"`
`"context": {`
` "path": "{field}",`
` "value": "{value}"`
`}` }`
</td>
</tr>
<tr>
<td>Unexpected field in item request</td>
<td>400</td>
<td>
`"code": "unexpected-field"`
`"message": "The request body contains an unexpected field "`
`"context":{`
` { "field: ": "{field}"` }`
</td>
</tr>
<tr>
<td>Item after changes missing label or description </td>
<td>400</td>
<td>
`"code": "missing-labels-and-descriptions"`
`"message": "Item requires at least a label or a description in a language"`
</td>
</tr>
<tr>
<td>When label, description or alias fields are selected but not filled (aka, empty)</td>
<td>400</td>
<td>
`"code": "label/description/alias-empty"`
`"message": "Label/Description/Alias list must not be empty"`
`"context": {`
` "language": "{language_code}"`
`}` }`
</td>
</tr>
<tr>
<td> Label and description have same value</td>
<td>400</td>
<td>
` `"code": "label-description-same-value"`,
`"message": "Label and description for language '{language_code}' can not have the same value"`
`"context": {
` "language": "{language}" }`
</td>
</tr>
<tr>
<td> Label/description/alias too long</td>
<td>400</td>
<td>
`"code": "label/description/alias-too-long"`
`"message": "Description/label/alias must be no more than {limit} characters long"`
` `"context": { "value": "{description/labellabel/desc/alias}", "language": "{language_code}" ,, "character-limit": "{limit}"}` }`
</td>
</tr>
<tr>
<td> Label/description/alias invalid</td>
<td>400</td>
<td>
`"code": "invalid-label/description/label/alias"`
`"message": "Not a valid label/description/label/alias: {description/labellabel/desc/alias}"`
` `"context": { "value": "{description/labellabel/desc/alias}", "language": "{language_code}" }`
</td>
</tr>
<tr>
<td> Invalid language code</td>
<td>400</td>
<td>
`"code": "invalid-language-code"`
`"message": "Not a valid language code: {language_code}"`
` `"context": { "path": "{field}", "language_code": "{language_code}" }`
</td>
</tr>
<tr>
<td> Duplicate alias</td>
<td>400</td>
<td>
`"code": "duplicate-alias"`
`"message": "Alias list contains a duplicate alias: '{alias}'"`
`"context": { "language_code": "{language_code}", "alias": "{alias}" }`
</td>
</tr>
<tr>
<td> Item with label and description already exists</td>
<td>400</td>
<td>
`"code": "item-label-description-duplicate"`
`"message": "Item '{duplicate_item_id}' already has label '{label}' associated with language code '{language}', using the same description text"`
`"context": { "language": "{language}", "label": "{label}", "description": "{description}", "matching-item-id": "{duplicate_item_id}"}` }`
</td>
</tr>
<tr>
<td>Sitelink conflict</td>
<td>409</td>
<td>
`{ `"code": "sitelink-conflict", `
`"message": "Sitelink is already being used on {other_item_id}", `
`"context": { "site": "{site_id}", "matching-item-id": "{duplicate_item_id}"}`}` }`
</td>
</tr>
<tr>
<td>Sitelink title field not provided</td>
<td>400</td>
<td>
`{ `"code": "sitelink-data-missing-title", "message": "Mandatory sitelink title missing","context": { "site": "{site_id}"}}`e"`
`"message": "Mandatory sitelink title missing"`
`"context": { "site": "{site_id}" }`
</td>
</tr>
<tr>
<td>title is empty</td>
<td>400</td>
<td> `{"code": "title-field-empty", "message": "Title must not be empty","context": { "site": "{site_id}"}}`
`"code": "title-field-empty"`
`"message": "Title must not be empty"`
`"context": { "site": "{site_id}" }`
</td>
</tr>
<tr>
<td>Invalid title</td>
<td>400</td>
<td> `{
`"code": "invalid-title-field", `
`"message": "Not a valid input for title field'","`
`"context": { "title": "{title}", "site": "{site_id}"}}` }`
</tr>
<tr>
<td>Value provided as a badge is not an item ID</td>
<td>400</td>
<td>`{
`"code": "invalid-input-sitelink-badge", `
`"message": "Badge input is not an item ID: {value}",`
`"context": { "badge": "{value}", "site": "{site_id}"}}` }`
</td>
</tr>
<tr>
<td>itemItem provided is not allowed as a site link badge </td>
<td>400</td>
<td>`{
`"code": "item-not-a-badge", `
`"message": "Item ID provided as badge is not allowed as a badge: {item_id}","context": { "badge": "{item_id}","site": "{site_id}"}}`
`"context": { "badge": "{item_id}", "site": "{site_id}" }`
</td>
</tr>
<tr>
<td>value of badges field is not a list</td>
<td>400</td>
<td>`{"code": "invalid-sitelink-badges-format", "message": "Value of badges field is not a list","context": { "site": "{site_id}"} }`<td>
`"code": "invalid-sitelink-badges-format"`
`"message": "Value of badges field is not a list"`
`"context": { "site": "{site_id}" }`
</td>
</tr>
<tr>
<td>Title does not exist on the given site</td>
<td>400</td>
<td>`{"code": "title-does-not-exist<td>
`"code": "title-does-not-exist"`
`"message": "Page with title {title} does not exist on the given site"`
`"context": { "site": "{site_id}", "message": "Page with title {"title} does not exist on the given site","context": { "site": "{site_id}","title": "{title}} }`}" }`
</td>
</tr>
</table>
**Notes**
- Automated edit summary to be of the type: `/* wbeditentity-create-item:0| */`
- How Action API does it: https://www.wikidata.org/w/api.php?action=help&modules=wbeditentity
**Task breakdown**
* add to OAS
* create ItemDeserializer (plugs together all the existing deserializers for labels, descriptions, aliases, statements, sitelinks)
* create `ItemCreator` interface with a `create( Item $item, EditMetadata $editMetadata ): ItemRevision;` and implementation. We can likely reuse the existing `EntityUpdater` class which might then need a better name.
* happy path
* include revision ID and last modified date
* edit summary
* authorization
* add new method to `PermissionChecker`: TBD
... to be continued ...
* spec tests
* mark production ready
**Questions**
* the GET /item... route contains `"type": "item"`. Do we require this field for POST /item requests? Do we ignore it? Do we fail if the request contains something other than "item" for the "type" field?