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).