REST API: How to respect 'name' during POST?

All,

I am using the document REST API to create (insert) Customers. My JSON data is this:

{
 "name": "my_customer_id",
 "customer_name": "Acme Corp",
 "idx": 0,
 "territory": "United States",
 "customer_group": "Individual",
 "naming_series" : ""
}

I am executing this exact POST, several times, over and over.

Expected Results:

  • First POST should succeed.
  • Second POST should fail. Because it is a duplicate Customer (same name as previous, which is the primary key)

Actual Results:

  • First POST succeeds. But the name is not ā€œmy_customer_idā€. ERPNext writes ā€œAcme Corpā€ as the name
  • Second POST succeeds. It uses a new name = ā€œAcme Corp 2ā€
  • Third POST succeeds. It uses a new name = ā€œAcme Corp 3ā€

Question

Can anyone see where Iā€™ve made a mistake? I would like the REST API to respect the name I am providing. So that duplicate Customers are not created by accident.

Iā€™m assuming Iā€™ve made some kind of silly mistake.

(here is the actual curl, for those curious)

curl --request POST \
  --url http://localhost:8000/api/resource/Customer \
  --header 'Authorization: token 12345:67890' \
  --header 'Content-Type: application/json' \
  --header 'Cookie: system_user=yes; full_name=Guest; user_id=Guest; user_image=' \
  --cookie 'sid=Guest; system_user=yes; full_name=Guest; user_id=Guest; user_image=' \
  --data '{
 "name": "my_customer_id",
 "customer_name": "Acme Corp",
 "idx": 0,
 "territory": "United States",
 "customer_group": "Individual",
 "naming_series" : ""
}

change doctype Customer naming rule to Prompt

That would solve the REST problem. But introduce another. I donā€™t want Users manually choosing the name field of Customers, when they do data-entry in the web browser.

I like the auto-generated Naming Series:

  • CUST-2021-0001
  • CUST-2021-0002
  • CUST-2021-0003

However, Iā€™m concerned about the API caller making a mistake. Instead of creating 1 new customer named ā€œAcme Corpā€ (with an auto-generated name) it might 2 new customers. Or 3. Or 100 new ones?

That would be a huge mess. :grimacing:

set customer_name field as Unique via customize form can prevent creating duplicate customer records with same customer name.

Thanks for taking time to provide ideas and feedback, @szufisher. :hugs:

I agree the best workaround is to make a DocField unique. Then SQL will throw an error on the 2nd POST. And prevent the duplicates from happening.

Later, I may try to hack the REST API code. And teach it to behave differently when an explicit value of name is passed to the API.

did you hack it successfully?
I am noticing, that I cannot teach the REST API to use my ID (name) or use a naming_series.

Concretely I am POSTing Suppliers (like this example):

{
    "naming_series": "SUP-",
    "name": "unksuppuid",
    "supplier_name": "Unknown Supplier" ,
    "supplier_type": "Company",
    "supplier_group": "Alle Lieferantengruppen"
}

But neither itā€™s taking SUP-##### nor unksuppuid for ā€œnameā€.

It just uses the supplier_name what is definitely not useful now.

I did a partial hack. I added code that forbids anyone from calling POST, and in the payload, including a ā€˜nameā€™ value that already exists. Screenshot below. Method is handle() within the file ā€˜api.pyā€™

Supplier and Customer are special cases. Not only do they have ā€˜Naming Seriesā€™, but they have special controls in ā€˜Selling Settingsā€™ and ā€˜Buying Settingsā€™.

Screenshot below of ā€˜Buying Settingsā€™, which applies to your case. Suppliers can either get their name from ā€˜Supplier Nameā€™ or ā€˜Naming Seriesā€™. This will override anything you pass in an API call.

thanks alot for your insights, @brian_pond

I am not sure, if you reached the goal with it, to define the name from the API call? (Well, I am understanding the exception, when there is a duplicate), but name is anyway a primary key, isnā€™t it?

When using the Import interface, there is no problem to define name and I just expected the REST API to behave the same wayā€¦ but is there a trick, to define the name value?

Sorry, if I am missing it from your snippet .

I just have had a look at the current codeā€¦ I am not very farmiliar with frappe/python yet, but when I refer the comment from get_doc
image

It seems, that the API is just not providing the 2nd parameter as a name (if it would have been given)
image

Sure, the property name will be in data, but probably the ORM wont respect this by default, if not explicitely given.

hah ā€¦ I finally found something interesting:

ā†’

I can provide the __newname dummy property, which will be read here to be used as the new name.
image

If you POST this record a 2nd time, youā€™ll get the DuplicateEntryError exception (as name is primary key).
image

Was currently testing this now with Purchase Invoice but I expect it will work with other DocTypes as well.

2 Likes

Youā€™re correct; name is a primary key. However, it was being ignored in the API call.

So I wanted a way to tell the Caller: ā€œHi, you are passing a ā€˜nameā€™ in a POST, but that name already exists. Donā€™t do that. Why did you think this ā€˜nameā€™ is available?ā€

This forced the caller to rethink what they were doing. Otherwise, without this code, the POST succeeded. And the Caller might never realize the name they passed was ignored.

This was just a temporary fix, to prevent my API callers from doing strange things.

What youā€™re doing, -setting- the name value during a call? Thatā€™s awesome. That is what Iā€™d hoped to figure out later, when I had time to return to this issue. :star_struck:

Very interested in trying your __newname solution.

Yea, I think the __newname property is exactly what you were looking for, when I interprete this correctly :slight_smile:

At least it was exactly what I was looking for ā€¦ and thinking that I understood you the same way :wink:

I also tried the API Call with Supplier, which worked pretty well (as expected, but now proven)ā€¦ so it will (imho) work for the most DocTypes (at least those, which donā€™t have an explicit coding to avoid that).