400 Error Updating a product

JamesTankersley
Shopify Partner
31 1 3

Getting a 400 error on product update. The Content-Type header is set to application/json, get calls to product count work using the same credentials. Kinda puzzled. Using C# .net 7 HttpClient to make the call.  Calling to 

https://{mystore}.myshopify.com/admin/api/2023-04/products/{product_id}.json anyone else run into this issue?

Replies 7 (7)

1080
Shopify Partner
292 8 42

@JamesTankersley  I think you are missing the Admin api access Auth flow.
I have no issue when  modify product data.

snakecase
Shopify Partner
18 4 8

Hi James,

Here the list of the things that I check when a 400 happens to me:

- Do I use the right method to call the endpoint? GET / POST ?

- Does my app has the scope necessary to write products?

- Is there any information in the response? Shopify can add context/reasons when the API replies an error.

 

To help you more, it would be good if you could share the code that you wrote to send the request and the response content and headers that you receive.

 

 

 

JamesTankersley
Shopify Partner
31 1 3

Also important to note it is a custom app, not public. The permissions are as follows:
write_content
write_customers
write_fulfillments
write_gift_cards
write_inventory
read_locations
write_orders
write_products
write_script_tags
write_shipping
write_themes
read_content
read_fulfillments
read_gift_cards
read_inventory
read_orders
read_products
read_script_tags
read_shipping
read_themes
write_locations
write_metaobject_definitions
read_metaobject_definitions
write_metaobjects
read_metaobjects
write_product_feeds
read_product_feeds
write_product_listings
read_product_listings

 

Response Headers ({redacted} = id numbers removed):

 

 

 

{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.HttpConnectionResponseContent, Headers:
{
  Date: Thu, 01 Jun 2023 22:21:06 GMT
  Transfer-Encoding: chunked
  Connection: keep-alive
  X-Sorting-Hat-PodId: 47
  X-Sorting-Hat-ShopId: {redacted}
  Referrer-Policy: origin-when-cross-origin
  X-Frame-Options: DENY
  X-ShopId: {redacted}
  X-ShardId: 47
  X-Stats-UserId: 
  X-Stats-ApiClientId: {redacted}
  X-Stats-ApiPermissionId: {redacted}
  X-Shopify-API-Terms: By accessing or using the Shopify API you agree to the Shopify API License and Terms of Use at https://www.shopify.com/legal/api-terms
  X-Shopify-API-Version: 2023-04
  HTTP_X_SHOPIFY_SHOP_API_CALL_LIMIT: 1/400
  X-Shopify-Shop-Api-Call-Limit: 1/400
  Strict-Transport-Security: max-age=7889238
  Server-Timing: processing;dur=53
  Server-Timing: cfRequestDuration;dur=141.000032
  X-Shopify-Stage: production
  Content-Security-Policy: default-src 'self' data: blob: 'unsafe-inline' 'unsafe-eval' https://* shopify-pos://*; block-all-mixed-content; child-src 'self' https://* shopify-pos://*; connect-src 'self' wss://* https://*; frame-ancestors 'none'; img-src 'self' data: blob: https:; script-src https://cdn.shopify.com https://cdn.shopifycdn.net https://checkout.shopifycs.com https://api.stripe.com https://mpsnare.iesnare.com https://appcenter.intuit.com https://www.paypal.com https://js.braintreegateway.com https://c.paypal.com https://maps.googleapis.com https://www.google-analytics.com https://v.shopify.com 'self' 'unsafe-inline' 'unsafe-eval'; upgrade-insecure-requests; report-uri /csp-report?source%5Baction%5D=update&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fproducts&source%5Bsection%5D=admin_api&source%5Buuid%5D=fb8ef5ec-7071-4444-9c71-13de06de2bea
  X-Content-Type-Options: nosniff
  X-Download-Options: noopen
  X-Permitted-Cross-Domain-Policies: none
  X-XSS-Protection: 1; mode=block; report=/xss-report?source%5Baction%5D=update&source%5Bapp%5D=Shopify&source%5Bcontroller%5D=admin%2Fproducts&source%5Bsection%5D=admin_api&source%5Buuid%5D=fb8ef5ec-7071-4444-9c71-13de06de2bea
  X-Dc: gcp-us-east4,gcp-us-central1,gcp-us-central1
  X-Request-ID: fb8ef5ec-7071-4444-9c71-13de06de2bea
  CF-Cache-Status: DYNAMIC
  Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=z1Nxf0%2FEZNw0Ak3fTDqzXY47Y%2F2%2BtG17Qw%2BpSOZB2koimd79CYAZlhTJrXVAosehhk5KpIongLqQOn0hIQTXelm1wk5z32rznnFQkwrd%2F%2BQla43JVcVXGwAF%2B5Q3rqf6ydg2gsw8JF%2FdtA%3D%3D"}],"group":"cf-nel","max_age":604800}
  NEL: {"success_fraction":0.01,"report_to":"cf-nel","max_age":604800}
  Server: cloudflare
  CF-RAY: 7d0ad903d90f575e-IAD
  Alt-Svc: h3=":443"; ma=86400
  Content-Type: application/json; charset=utf-8
}}

 

 

 

The body was simply "Bad Request"

 

Code to make request:

 

 

 

private static async Task<HttpResponseMessage> CreateWebRequest(string endPoint, Int32 contentLength, string verb, HttpContent? content)
        {
            HttpResponseMessage message;

            HttpClientHandler handler = new()
            {
                Credentials = GetCredential(endPoint!, apiUsername!, apiPassword!)
            };
            HttpClient client = new(handler, true);

            using (client)
            {
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(
                    new MediaTypeWithQualityHeaderValue("application/json"));
                client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)");
                client.BaseAddress = new Uri(endPoint);

                message = verb switch
                {
                    "GET" => await client.GetAsync(client.BaseAddress),
                    "POST" => await client.PostAsync(client.BaseAddress, content),
                    "PUT" => await client.PutAsync(client.BaseAddress, content),
                    _ => await client.GetAsync(client.BaseAddress),
                };
            }

                return message;
        }

 

 

 

 

Credentials:

 

 

 

private static CredentialCache GetCredential(string url, string username, string password)
        {
            ServicePointManager.Expect100Continue = true;
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            var credentialCache = new CredentialCache
            {
                {
                    new Uri(url),
                    "Basic"
                ,
                    new NetworkCredential(username, password)
                }
            };
            return credentialCache;
        }

 

 

 

 

 

snakecase
Shopify Partner
18 4 8

From your code sample, I can see that you are using a Basic authentication for your request.

 

 

            var credentialCache = new CredentialCache
            {
                {
                    new Uri(url),
                    "Basic"
                ,
                    new NetworkCredential(username, password)
                }
            };

 

 

Shopify use an oauth authentication system. Consequently you need an access token obtained via the API key and and API secret of the custom application that you are building.

 

To get an overview on authentication, you can have a look at Shopify documentation: Authentication and authorization overview

 

To generate an Access Token for a custom application in a specific store you can follow the documentation Access tokens for custom apps in the Shopify admin. Or this tutorial Get your Shopify Access Token.

 

Once you have an access token you can set it to the X-Shopify-Access-Token header of your requests and from there it should work

 

curl -X GET \
https://{shop}.myshopify.com/admin/api/2023-04/products.json \
-H 'Content-Type: application/json' \
-H 'X-Shopify-Access-Token: {access_token}'
 

 I hope that help you to move forward.

JamesTankersley
Shopify Partner
31 1 3

It seams as though I was not getting the whole picture from the body in Visual Studio. The body simply said Bad Request. I took the values from my code, headers and content and put them in postman and got a 400 but the body was more informative.

 

 

{
    "errors": {
        "metafield": "Required parameter missing or invalid"
    }
}

 

Ok, that's great so, I looked at the body of the request and I can't see what's missing. According to the curl sample in the api guide I am sending too much. I even tried the json from the example on the api guide and it still said the same error message.

 

Here is my json content, do you see (or anyone) anything missing? Some info {redacted}

{
    "id": {redacted},
    "namespace": "global",
    "key": "description_tag",
    "value": "While weaving together Clare\u0026rsquo;s story and Francis\u0026rsquo;s story, Margaret Carney draws special attention to Clare\u0026rsquo;s significant contribution to\u0026#160;the Franciscan world in the many years following Francis\u0026rsquo;s death.\u0026#160;Far from merely reflecting Francis\u0026rsquo;s light, Clare had her own\u0026#160;charism, \u0026ldquo;a gift bestowed by the Spirit of the Lord and given\u0026#160;to her in a fullness and forcefulness that was hers alone.\u0026quot;\u0026#160; This book will introduce St. Clare of Assisi to those who do not know her and those who wish to know her better. It leads the reader from Clare\u0026#39;s\u0026#160;birth to her death. While taking account of modern scholarship, Sr. Margaret Carney tells the story of this medieval woman in a way readers today can understand.",
    "value_type": "string",
    "description": null,
    "owner_id": {redacted},
    "created_at": "2020-11-24T09:53:18-05:00",
    "updated_at": "2021-04-20T13:04:01-04:00",
    "owner_resource": "product",
    "type": "string"
}

 

JamesTankersley
Shopify Partner
31 1 3

I should give a full json example body, my apologies.  I have gone back and forth with postman working and getting a 200 response while it still gets a 400 in VS and some working in VS but getting the 400 { "errors": { "metafield": "Required parameter missing or invalid" } } in POSTMAN. It's inconsistent.

Full JSON body:

{
    "metafield": {
        "id": {redacted},
        "namespace": "global",
        "key": "Dimensions",
        "value": "5.5in X 8.5in",
        "value_type": "string",
        "description": null,
        "owner_id": {redacted},
        "created_at": "2020-11-24T09:57:23-05:00",
        "updated_at": "2022-08-07T00:20:26-04:00",
        "owner_resource": "product",
        "type": "string",
        "admin_graphql_api_id": "{redacted}"
    }
}

 

 

Majid1225
Shopify Partner
2 0 0

First of all, if it's working through postman then it means you are going something wrong when you call from VS.

Would you like to call through C#-RestSharp Library?

Second in metafield json you are using "string" type which is not supported type for metafields. 
For string value you will use "single_line_text_field" type. Also need to update the type of "Dimensions" first of all. 
Maybe It will help out you.