Repository: saleor/saleor

Issue:
Unclear country input expectation for GraphQL checkout address attach mutation
### What I'm trying to achieve
I'm trying to create an shipping or billing address via GraphQL checkout attach. But it's unclear what is expected in the `AddressInput.country` field.

### Steps to reproduce the problem
1. Call `Mutations.checkoutShippingAddressUpdate` using string for country input like "USA", "United States"
2. We get back errors from Django GraphLQ saying that "invalid country code"

### What I expected to happen
There seems to validation going on in `saleor/graphql/account/i18n.py` that checks country string with phone number as well as converts country string to country code and checks against list of valid country codes. The problem, I see here is that because the GraphQL API expects a any string, it's not obvious what the correct string should be. I would make it a just to expect the country code instead and link in the documentations what the expected values are to make it easier for developers.

### Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
https://www.dropbox.com/s/eow0x246dru5ga6/Screenshot%202019-07-16%2013.22.55.png?dl=0
https://www.dropbox.com/s/02w3fxi1r1x38ih/Screenshot%202019-07-16%2013.30.23.png?dl=0

**System information**
Operating system: MacOS
Browser: Chrome 75



Discussion:
It is expecting a two letter country code (ISO 3166-1), e.g. `US`, `PL`, `FR`, etc.
So it seems that there is a wrong input type for the `country` field in `AddressInput` type. Instead of `String` it should use the `CountryCode` enum.
Yea, I agree. I think it should be Enum of CountryCode to avoid confusion.

Resolving patch:
diff --git a/saleor/graphql/account/i18n.py b/saleor/graphql/account/i18n.py
--- a/saleor/graphql/account/i18n.py
+++ b/saleor/graphql/account/i18n.py
@@ -1,7 +1,5 @@
 from django.core.exceptions import ValidationError
-from django_countries import countries
 
-from ...account.error_codes import AccountErrorCode
 from ...account.forms import get_address_form
 from ...account.models import Address
 from ...account.validators import validate_possible_number
@@ -28,17 +26,7 @@ def validate_address(cls, address_data: dict, instance=None):
                     }
                 ) from exc
 
-        country_code = address_data.get("country")
-        if country_code in countries.countries.keys():
-            address_form, _ = get_address_form(address_data, address_data["country"])
-        else:
-            raise ValidationError(
-                {
-                    "country": ValidationError(
-                        "Invalid country code.", code=AccountErrorCode.INVALID
-                    )
-                }
-            )
+        address_form, _ = get_address_form(address_data, address_data.get("country"))
 
         if not address_form.is_valid():
             raise ValidationError(address_form.errors.as_data())
diff --git a/saleor/graphql/account/types.py b/saleor/graphql/account/types.py
--- a/saleor/graphql/account/types.py
+++ b/saleor/graphql/account/types.py
@@ -17,7 +17,7 @@
 from ..core.utils import get_node_optimized
 from ..decorators import one_of_permissions_required
 from ..utils import format_permissions_for_display
-from .enums import CustomerEventsEnum
+from .enums import CountryCodeEnum, CustomerEventsEnum
 
 
 class AddressInput(graphene.InputObjectType):
@@ -29,7 +29,7 @@ class AddressInput(graphene.InputObjectType):
     city = graphene.String(description="City.")
     city_area = graphene.String(description="District.")
     postal_code = graphene.String(description="Postal code.")
-    country = graphene.String(description="Country.")
+    country = CountryCodeEnum(description="Country.")
     country_area = graphene.String(description="State or province.")
     phone = graphene.String(description="Phone number.")
 


Test patch:
diff --git a/tests/api/test_account.py b/tests/api/test_account.py
--- a/tests/api/test_account.py
+++ b/tests/api/test_account.py
@@ -1895,7 +1895,7 @@ def test_create_address_mutation(
     staff_api_client, customer_user, permission_manage_users
 ):
     query = """
-    mutation CreateUserAddress($user: ID!, $city: String!, $country: String!) {
+    mutation CreateUserAddress($user: ID!, $city: String!, $country: CountryCode!) {
         addressCreate(userId: $user, input: {city: $city, country: $country}) {
             errors {
                 field
diff --git a/tests/api/test_checkout.py b/tests/api/test_checkout.py
--- a/tests/api/test_checkout.py
+++ b/tests/api/test_checkout.py
@@ -978,28 +978,6 @@ def test_checkout_shipping_address_update_without_phone_country_prefix(
     assert not data["errors"]
 
 
-def test_checkout_shipping_address_update_invalid_country_code(
-    user_api_client, checkout_with_item, graphql_address_data
-):
-    checkout = checkout_with_item
-    assert checkout.shipping_address is None
-    checkout_id = graphene.Node.to_global_id("Checkout", checkout.pk)
-
-    shipping_address = graphql_address_data
-    shipping_address["country"] = "CODE"
-    variables = {"checkoutId": checkout_id, "shippingAddress": shipping_address}
-
-    response = user_api_client.post_graphql(
-        MUTATION_CHECKOUT_SHIPPING_ADDRESS_UPDATE, variables
-    )
-    content = get_graphql_content(response)
-    data = content["data"]["checkoutShippingAddressUpdate"]
-    assert data["errors"][0]["message"] == "Invalid country code."
-    assert data["errors"][0]["field"] == "country"
-
-    assert data["checkoutErrors"][0]["code"] == CheckoutErrorCode.INVALID.name
-
-
 def test_checkout_billing_address_update(
     user_api_client, checkout_with_item, graphql_address_data
 ):