I discovered that documents created via the ERPNext rest api are not getting validated. For example, a non-existent document can be referenced in a link field and the doc still get’s created!
Is there a flag that can be used to ensure docs created via rest api are validated ?
Thanks for your reply. Yes I’m sure it’s a link field. I was referring to POST requests, not GET. For instance, the doc below was created via API but the value for Terminal ID doesn’t exist!
@wale
Difficult to know whether these are bugs, “working as intended”, or simply considered non-issues by the maintainers.
Like you, I’ve also encountered many strange behaviors with the APIs and document model. Here’s an easy one:
Create a POST to the Supplier doctype.
Pass the following JSON payload:
{
"name": "this will be ignored",
"supplier_name": "Acme Supply Co.",
"supplier_group": "Distributor",
"supplier_type": "Individual",
"foo": "so will this",
"bar": "and this too"
}
Send this POST, and you will receive back an HTTP 200; no warnings.
The ‘name’ key is silently ignored because the DocType is set to choose a name automatically based on the Naming Series. The HTTP response will have a completely different value for ‘name’.
The keys ‘foo’ and ‘bar’ are silently ignored too, because there are no such DocFields in the Supplier document.
This particular lack of validation drove me crazy during a recent project. People were calling my APIs, expecting that the ERP saved all the values transmitted. When in fact, they were silently discarded. Ultimately, I had to just start adding code to document.py and api.py. And create new validation checks to reject invalid API calls, like the one above.
Unrelated to APIs specifically, there are other hidden “gotchas” in the document model. For example, the optional ‘validate()’ controller method is called before the Document checks that mandatory fields are populated. So, when writing code in validate(), you could be working with None or 0 values. Values that won’t get recognized and rejected until later in the process of saving a record.
I suspect that’s because you’re using a Standard Doctype (ie Item). The API call also fails at our end when we try creating an Item with non-existent Item Group and that’s how it should be. The issue however still persists with Custom doctypes. Please test this on a Custom Doctype
there is an option called ignore_links that can be called during an insert or save event . I dont know how exactly it works with api . but it can be the problem
{
"session_expired": 1,
"exc_type": "LinkValidationError",
"exc": "[\"Traceback (most recent call last):\\n File \\\"/erpnext/mybench/apps/frappe/frappe/app.py\\\", line 68, in application\\n response = frappe.api.handle()\\n File \\\"/erpnext/mybench/apps/frappe/frappe/api.py\\\", line 177, in handle\\n doc = frappe.get_doc(data).insert()\\n File \\\"/erpnext/mybench/apps/frappe/frappe/model/document.py\\\", line 258, in insert\\n self._validate_links()\\n File \\\"/erpnext/mybench/apps/frappe/frappe/model/document.py\\\", line 874, in _validate_links\\n frappe.throw(_(\\\"Invalid link. Could not find {0}\\\").format(msg),\\n File \\\"/erpnext/mybench/apps/frappe/frappe/__init__.py\\\", line 462, in throw\\n msgprint(msg, raise_exception=exc, title=title, indicator='red', is_minimizable=is_minimizable, wide=wide, as_list=as_list)\\n File \\\"/erpnext/mybench/apps/frappe/frappe/__init__.py\\\", line 441, in msgprint\\n _raise_exception()\\n File \\\"/erpnext/mybench/apps/frappe/frappe/__init__.py\\\", line 376, in _raise_exception\\n raise raise_exception(msg)\\nfrappe.exceptions.LinkValidationError: Invalid link. Could not find Baz: 12345\\n\"]",
"_server_messages": "[\"{\\\"message\\\": \\\"Invalid link.
Could not find Baz: 12345\\\", \\\"indicator\\\": \\\"red\\\", \\\"raise_exception\\\": 1}\"]"
}
(when I changed my JSON payload to use a real value, I verified that I received back a 200)
Thanks for your responses and tests. I’ve spent a good part of the weekend trying to diagnose the issue but still haven’t gotten exactly what it is. It however must be somehow related to that particular field because when I rename it to something else (e.g. terminalid1) the validation occurs as expected but once I revert to the original fieldname (terminalid), there’s no validation!
Any ideas?
Its important for us to use the correct field name
First, execute a 'bench migrate' command, to ensure the SQL schema is synchronized.
Next, examine the SQL table itself. Delete any leftover columns that no longer exist
(remember, the framework -adds- columns during ‘bench migrate’, but never deletes and cleans-up any unused columns.)
Run a 'bench clear-cache' command.
Delete the Python bytecode files. These often cause me headaches. The bytecode files (those with extension *.pyc), sometimes don’t reflect the real, current Python code. I remove them by changing to my frappe-bench directory, and running this command.
find . -name *.pyc -delete
Restart the Frappe web server.
This should clear up any ‘cached’ behaviors, and ensure that everything is running as-per-code.
If this doesn’t do the trick? Then I’d suggest getting a 2nd person involved. Have a developer review your DocTypes and code, and perhaps debug the Python code from start to finish.
Trust y’all had a great weekend. So after much investigation and testing, I think I found the bug. If you add another field to your doctype and set that field to ‘Fetch From’ the link field, the link field is no longer validated!
So just for clarity, you can replicate using the following steps:
Create a doctype with 2 fields… Field A (Link Field) and Field B (Data Field)
Set the ‘Fetch From’ option in Field B so that it fetches it’s value from a valid field in the doctype that Field A links to (ie field_a.some_valid_field)
Make an API call to create the doctype using a non-existent value for Field A
You will notice the doc gets created successfully without validating the link!
Wow… this is really puzzling. Guess I’m better off looking into writing custom APIs to meet the immediate need while I keep digging to uncover the source of this issue