goshippo / shippo-javascript-sdk

MIT License
7 stars 1 forks source link

Zod errors on response from shippoClient.shipments.create #34

Closed alsoscotland closed 4 months ago

alsoscotland commented 4 months ago

Thank you for the v2.2.4 update. customsDeclarations are working fine now. Still working through code to get back to parity with v1.7.1

Using the await shippoClient.shipments.create method I was previously passing saved shippo address objects to the addressTo field for and doing so now I am receiving another Zod error.

It appears that this method used to accept the full object for addressTo and now expects only an objectId

After adjusting to use the objectId of the address I am seeing new validation errors on the response. Please document if as an end-user I should permanently alter these flows to use object ids moving forward.

It may also be worth noting that previously saved address objects in my database came from shippo with latitude/longitude as numbers. They API seems to expect strings for these properties now according to zod errors when I was passing the

request object

{
 "addressFrom": {
   "zip": "<redacted>",
   "city": "<redacted>",
   "name": "<redacted>",
   "test": false,
   "email": "",
   "phone": "<redacted>",
   "state": "<redacted>",
   "company": "",
   "country": "<redacted>",
   "street1": "<redacted>",
   "street2": "",
   "street3": "",
   "latitude": <redacted>, // type number here
   "metadata": "",
   "longitude": <redacted>, // type number here 
   "object_id": "<redacted>",
   "street_no": "",
   "is_complete": true,
   "object_owner": "<redacted>",
   "is_residential": true,
   "object_created": "<redacted>",
   "object_updated": "<redacted>",
   "validation_results": {
     "is_valid": true,
     "messages": <redacted>
   }
 },
 "addressTo": "<redacted>",
 "customsDeclaration": "<redacted>",
 "parcels": [
   {
     "distanceUnit": "in",
     "height": "2",
     "length": "9.25",
     "massUnit": "oz",
     "weight": "8",
     "width": "6.25"
   }
 ],
 "async": false,
 "extra": {
   "qrCodeRequested": true
 }
}

Zod response error

{
"status": "rejected",
"reason": {
"writeToLog": false,
"originalError": {
    "name": "SDKValidationError",
    "cause": {
    "issues": [
        {
        "code": "invalid_type",
        "expected": "string",
        "received": "object",
        "path": [
            "rates",
            2,
            "servicelevel",
            "parent_servicelevel"
        ],
        "message": "Expected string, received object"
        },
        {
        "code": "invalid_type",
        "expected": "string",
        "received": "object",
        "path": [
            "rates",
            3,
            "servicelevel",
            "parent_servicelevel"
        ],
        "message": "Expected string, received object"
        },
        {
        "code": "invalid_type",
        "expected": "string",
        "received": "object",
        "path": [
            "rates",
            4,
            "servicelevel",
            "parent_servicelevel"
        ],
        "message": "Expected string, received object"
        }
    ],
    "name": "ZodError"
}

addressTo errors when passing full objects:

"name": "SDKValidationError",
"cause": {
"issues": [
    {
    "code": "invalid_union",
    "unionErrors": [
        {
        "issues": [
            {
            "code": "invalid_type",
            "expected": "number",
            "received": "string",
            "path": [
                "addressTo",
                "latitude"
            ],
            "message": "Expected number, received string"
            },
            {
            "code": "invalid_type",
            "expected": "number",
            "received": "string",
            "path": [
                "addressTo",
                "longitude"
            ],
            "message": "Expected number, received string"
            }
        ],
        "name": "ZodError"
        },
        {
        "issues": [
            {
            "code": "invalid_type",
            "expected": "string",
            "received": "object",
            "path": [
                "addressTo"
            ],
            "message": "Expected string, received object"
            }
        ],
        "name": "ZodError"
        }
    ],
    "path": [
        "addressTo"
    ],
    "message": "Invalid input"
    }
],
"name": "ZodError"
}
richardebrain commented 4 months ago

i was experiencing this with international shipping also , although mine is coming from service_level , zod expect string but i am getting an object back while trying to create shipment

shippo-lueders commented 4 months ago

After adjusting to use the objectId of the address I am seeing new validation errors on the response. Please document if as an end-user I should permanently alter these flows to use object ids moving forward.

the short answer is no, you will not need to alter these flows. from the logs, it looks like it's expecting parent_servicelevel to be a complete object rather than a token. looking at the spec, it looks like the description is right but the type is wrong, will have this fixed today.

as for the lat/long, I'll investigate and update this ticket with an ETA

shippo-lueders commented 4 months ago

the parent_servicelevel issue should be resolved with https://www.npmjs.com/package/shippo/v/2.2.5

re: the lat/long, taking a closer look at the error

       "code": "invalid_type",
       "expected": "number",
       "received": "string",
       "path": [
           "addressTo",
           "latitude"
       ],
       "message": "Expected number, received string"

it sounds like it's expecting a number but the input was actually a string. looking at both the spec and actual results, lat/long is of numeric type.

It may also be worth noting that previously saved address objects in my database came from shippo with latitude/longitude as numbers.

can you confirm that lat/long is stored as numbers in your database and that they are not getting converting to string as part of the address input object?

as an aside, the input model of address when creating a shipment is not the same as the output model. specifically, there are no object_id, object_created, validation_results, etc fields, these are only part of the output model. sending them shouldn't be an issue, they will simply get dropped - but a new address will be created and returned in the shipment response.

alsoscotland commented 4 months ago

Interesting. The great news is that I am able to obtain rate quotes again as of v2.2.5 Thank you for the fast turnaround on these.

I do have a couple more follow up questions/observations:

they will simply get dropped - but a new address will be created and returned in the shipment response

Does that mean at this endpoint, and more importantly, across the other shippo API methods, when I pass objectIds I will get previously created objects, but when passing a complete object, new objects will be instantiated? I use similar, full-object request data for things like parcels and I would like to maintain consistent objectIds across all operations.

  1. I investigated further into the saved address data from my database and indeed the to address seems to have lat/long stored as strings while the from address has numbers. Both items were saved directly into my database from shippo responses and retrieved from the DB in an identical manner. the to address was saved as

    "latitude": "4<redacted>", // string here
    "longitude": "-7<redacted>", // string here
    "object_created": "2023-10-26T12:21:32.922Z",

the from address was saved as

"latitude": 3<redacted>, // number here
"longitude": -7<redacted>, // number here
"object_created": "2024-01-30T21:36:50.870Z"

Is it possible the behavior of the APIs changed between those dates?

shippo-lueders commented 4 months ago

Does that mean at this endpoint, and more importantly, across the other shippo API methods, when I pass objectIds I will get previously created objects, but when passing a complete object, new objects will be instantiated?

that's correct, if you want to re-use previously created objects, you'll need to just send the object id

re: lat/long, I'm realizing now that the spec is wrong - lat/long are not actually accepted inputs. you can see this by creating an address and passing in lat/long and if you don't validate the address by passing in validate=True, the return address won't have lat/long. if you do validate, the input lat/long are ignored and replaced, which you can see by passing in invalid lat/long for a known address.

shippo-lueders commented 4 months ago

https://www.npmjs.com/package/shippo/v/2.2.5

lat/long have been removed as address input parameters so you should no longer get the validation failure. feel free to re-open if you still see any issue

shippo-lueders commented 4 months ago

actually, something went wrong with publication, that package I linked was published two days ago, investigating

shippo-lueders commented 4 months ago

okay, really fixed now https://www.npmjs.com/package/shippo/v/2.2.6