Repository: saleor/saleor

Issue:
Bug: Cannot return null for non-nullable field Webhook.name.
### What are you trying to achieve?

Open app in dashboard.

It seems that name is optional https://docs.saleor.io/docs/3.x/api-reference/webhooks/inputs/webhook-create-input#code-style-fontweight-normal-webhookcreateinputbnamebcodestring-

But querying such webhooks would return error

### Steps to reproduce the problem

```graphql
mutation{
  webhookCreate(input:{targetUrl:"https://examples.site/", syncEvents:[SHIPPING_LIST_METHODS_FOR_CHECKOUT], app:"QXBwOjY5"}){
    errors{
      message
      field
    }
    webhook{
      name
    }
  }
}
```

```graphql
query App($id: ID!) {
  app(id: $id) {
    ...App
    aboutApp
    author
    permissions {
      code
      name
      __typename
    }
    dataPrivacy
    dataPrivacyUrl
    __typename
  }
}

fragment App on App {
  id
  name
  created
  isActive
  type
  homepageUrl
  appUrl
  manifestUrl
  configurationUrl
  supportUrl
  version
  accessToken
  privateMetadata {
    key
    value
    __typename
  }
  metadata {
    key
    value
    __typename
  }
  tokens {
    authToken
    id
    name
    __typename
  }
  webhooks {
    ...Webhook
    __typename
  }
  __typename
}

fragment Webhook on Webhook {
  id
  name
  isActive
  app {
    id
    name
    __typename
  }
  __typename
}
```

```
{
  "id": "QXBwOjY5",
  "PERMISSION_MANAGE_USERS": true,
  "PERMISSION_MANAGE_STAFF": true,
  "PERMISSION_IMPERSONATE_USER": true,
  "PERMISSION_MANAGE_APPS": true,
  "PERMISSION_MANAGE_OBSERVABILITY": true,
  "PERMISSION_MANAGE_CHECKOUTS": true,
  "PERMISSION_HANDLE_CHECKOUTS": true,
  "PERMISSION_HANDLE_TAXES": true,
  "PERMISSION_MANAGE_TAXES": true,
  "PERMISSION_MANAGE_CHANNELS": true,
  "PERMISSION_MANAGE_DISCOUNTS": true,
  "PERMISSION_MANAGE_GIFT_CARD": true,
  "PERMISSION_MANAGE_MENUS": true,
  "PERMISSION_MANAGE_ORDERS": true,
  "PERMISSION_MANAGE_PAGES": true,
  "PERMISSION_MANAGE_PAGE_TYPES_AND_ATTRIBUTES": true,
  "PERMISSION_HANDLE_PAYMENTS": true,
  "PERMISSION_MANAGE_PLUGINS": true,
  "PERMISSION_MANAGE_PRODUCTS": true,
  "PERMISSION_MANAGE_PRODUCT_TYPES_AND_ATTRIBUTES": true,
  "PERMISSION_MANAGE_SHIPPING": true,
  "PERMISSION_MANAGE_SETTINGS": true,
  "PERMISSION_MANAGE_TRANSLATIONS": true
}
```

```
{
  "errors": [
    {
      "message": "Cannot return null for non-nullable field Webhook.name.",
      "locations": [
        {
          "line": 55,
          "column": 3
        }
      ],
      "path": [
        "app",
        "webhooks",
        1,
        "name"
      ],
      "extensions": {
        "exception": {
          "code": "GraphQLError"
        }
      }
    }
  ],
  "data": {
    "app": {
      "id": "QXBwOjY5",
      "name": "Manage products",
      "created": "2023-03-27T15:39:57.879720+00:00",
      "isActive": true,
      "type": "LOCAL",
      "homepageUrl": null,
      "appUrl": null,
      "manifestUrl": null,
      "configurationUrl": null,
      "supportUrl": null,
      "version": null,
      "accessToken": null,
      "privateMetadata": [],
      "metadata": [],
      "tokens": [
        {
          "authToken": "Myd1",
          "id": "QXBwVG9rZW46Njk=",
          "name": "Default",
          "__typename": "AppToken"
        },
        {
          "authToken": "Dpqk",
          "id": "QXBwVG9rZW46NzA=",
          "name": "manage",
          "__typename": "AppToken"
        }
      ],
      "webhooks": null,
      "__typename": "App",
      "aboutApp": null,
      "author": null,
      "permissions": [
        {
          "code": "HANDLE_CHECKOUTS",
          "name": "Handle checkouts",
          "__typename": "Permission"
        },
        {
          "code": "HANDLE_PAYMENTS",
          "name": "Handle payments",
          "__typename": "Permission"
        },
        {
          "code": "HANDLE_TAXES",
          "name": "Handle taxes",
          "__typename": "Permission"
        },
        {
          "code": "IMPERSONATE_USER",
          "name": "Impersonate user.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_APPS",
          "name": "Manage apps",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_CHANNELS",
          "name": "Manage channels.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_CHECKOUTS",
          "name": "Manage checkouts",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_DISCOUNTS",
          "name": "Manage sales and vouchers.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_GIFT_CARD",
          "name": "Manage gift cards.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_MENUS",
          "name": "Manage navigation.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_OBSERVABILITY",
          "name": "Manage observability",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_ORDERS",
          "name": "Manage orders.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_PAGES",
          "name": "Manage pages.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_PAGE_TYPES_AND_ATTRIBUTES",
          "name": "Manage page types and attributes.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_PLUGINS",
          "name": "Manage plugins",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_PRODUCTS",
          "name": "Manage products.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_PRODUCT_TYPES_AND_ATTRIBUTES",
          "name": "Manage product types and attributes.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_SETTINGS",
          "name": "Manage settings.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_SHIPPING",
          "name": "Manage shipping.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_STAFF",
          "name": "Manage staff.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_TAXES",
          "name": "Manage taxes",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_TRANSLATIONS",
          "name": "Manage translations.",
          "__typename": "Permission"
        },
        {
          "code": "MANAGE_USERS",
          "name": "Manage customers.",
          "__typename": "Permission"
        }
      ],
      "dataPrivacy": null,
      "dataPrivacyUrl": null
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 3,
      "maximumAvailable": 50000
    }
  }
}
```

### What did you expect to happen?

Return null

### Logs

_No response_

### Environment

Saleor version: 3.13



Discussion:
I would like to work on this issue. 

Resolving patch:
diff --git a/saleor/graphql/webhook/types.py b/saleor/graphql/webhook/types.py
--- a/saleor/graphql/webhook/types.py
+++ b/saleor/graphql/webhook/types.py
@@ -147,7 +147,7 @@ class Meta:
 
 class Webhook(ModelObjectType[models.Webhook]):
     id = graphene.GlobalID(required=True)
-    name = graphene.String(required=True)
+    name = graphene.String(required=False)
     events = NonNullList(
         WebhookEvent,
         description="List of webhook events.",


Test patch:
diff --git a/saleor/graphql/webhook/tests/queries/test_webhook.py b/saleor/graphql/webhook/tests/queries/test_webhook.py
--- a/saleor/graphql/webhook/tests/queries/test_webhook.py
+++ b/saleor/graphql/webhook/tests/queries/test_webhook.py
@@ -14,6 +14,7 @@
       webhook(id: $id) {
         id
         isActive
+        name
         subscriptionQuery
         asyncEvents {
           eventType
@@ -167,3 +168,18 @@ def test_webhook_with_invalid_object_type(
     response = staff_api_client.post_graphql(QUERY_WEBHOOK, variables)
     content = get_graphql_content(response)
     assert content["data"]["webhook"] is None
+
+
+def test_webhook_without_name(
+    staff_api_client, webhook_without_name, permission_manage_apps
+):
+    query = QUERY_WEBHOOK
+    webhook_id = graphene.Node.to_global_id("Webhook", webhook_without_name.pk)
+    variables = {"id": webhook_id}
+    staff_api_client.user.user_permissions.add(permission_manage_apps)
+    response = staff_api_client.post_graphql(query, variables=variables)
+    content = get_graphql_content(response)
+    webhook_response = content["data"]["webhook"]
+    assert webhook_response["name"] is None
+    events = webhook_without_name.events.all()
+    assert len(events) == 1
diff --git a/saleor/tests/fixtures.py b/saleor/tests/fixtures.py
--- a/saleor/tests/fixtures.py
+++ b/saleor/tests/fixtures.py
@@ -6294,6 +6294,13 @@ def webhook(app):
     return webhook
 
 
+@pytest.fixture
+def webhook_without_name(app):
+    webhook = Webhook.objects.create(app=app, target_url="http://www.example.com/test")
+    webhook.events.create(event_type=WebhookEventAsyncType.ORDER_CREATED)
+    return webhook
+
+
 @pytest.fixture
 def any_webhook(app):
     webhook = Webhook.objects.create(