Skip to main content

Overview

EverShop uses REST-style mutations through API endpoints rather than GraphQL mutations. The GraphQL schema provides API URLs as fields on types, which you can use to perform create, update, and delete operations.

Mutation Pattern

Instead of traditional GraphQL mutations, EverShop provides API endpoint URLs in query responses:
query {
  product(id: "123") {
    productId
    name
    updateApi  # URL for updating this product
    deleteApi  # URL for deleting this product
  }
}
Then make REST API calls to these URLs:
// Update product
fetch(product.updateApi, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ name: 'New Name' })
})

// Delete product
fetch(product.deleteApi, {
  method: 'DELETE'
})

Cart Operations

Add Item to Cart

query {
  myCart {
    uuid
    addItemApi  # POST endpoint
  }
}
Request:
fetch(cart.addItemApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    product_id: 123,
    qty: 1,
    variant_options: {
      color: 1,
      size: 2
    }
  })
})

Update Cart Item Quantity

query {
  myCart {
    items {
      uuid
      qty
      updateQtyApi  # POST endpoint
    }
  }
}
Request:
fetch(cartItem.updateQtyApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    qty: 3
  })
})

Remove Item from Cart

query {
  myCart {
    items {
      uuid
      removeApi  # DELETE endpoint
    }
  }
}
Request:
fetch(cartItem.removeApi, {
  method: 'DELETE'
})

Add Shipping Address

query {
  myCart {
    addAddressApi  # POST endpoint
  }
}
Request:
fetch(cart.addAddressApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    address_type: 'shipping',
    full_name: 'John Doe',
    telephone: '555-1234',
    address_1: '123 Main St',
    city: 'Los Angeles',
    province: 'CA',
    postcode: '90210',
    country: 'US'
  })
})

Add Shipping Method

query {
  myCart {
    addShippingMethodApi
    availableShippingMethods {
      code
      name
      cost { value }
    }
  }
}
Request:
fetch(cart.addShippingMethodApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    method_code: 'flat_rate'
  })
})

Add Payment Method

query {
  myCart {
    addPaymentMethodApi
    availablePaymentMethods {
      code
      name
    }
  }
}
Request:
fetch(cart.addPaymentMethodApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    method_code: 'stripe'
  })
})

Add Contact Information

query {
  myCart {
    addContactInfoApi
  }
}
Request:
fetch(cart.addContactInfoApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    email: '[email protected]'
  })
})

Add Shipping Note

query {
  myCart {
    addNoteApi
  }
}
Request:
fetch(cart.addNoteApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    note: 'Please leave at the front door'
  })
})

Checkout

query {
  myCart {
    checkoutApi  # POST endpoint
  }
}
Request:
const response = await fetch(cart.checkoutApi, {
  method: 'POST'
})

const order = await response.json()
// Returns order details with order number

Customer Operations

Add Customer Address

query {
  currentCustomer {
    addAddressApi
  }
}
Request:
fetch(customer.addAddressApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    full_name: 'Jane Doe',
    telephone: '555-5678',
    address_1: '456 Oak Ave',
    city: 'San Francisco',
    province: 'CA',
    postcode: '94102',
    country: 'US',
    is_default: true
  })
})

Update Customer Address

query {
  currentCustomer {
    addresses {
      uuid
      updateApi
    }
  }
}
Request:
fetch(address.updateApi, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    telephone: '555-9999'
  })
})

Delete Customer Address

query {
  currentCustomer {
    addresses {
      uuid
      deleteApi
    }
  }
}
Request:
fetch(address.deleteApi, {
  method: 'DELETE'
})

Product Management (Admin)

Update Product

query {
  product(id: "123") {
    uuid
    updateApi
  }
}
Request:
fetch(product.updateApi, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'Updated Product Name',
    price: 29.99,
    status: 1,
    description: 'New description',
    sku: 'PROD-001'
  })
})

Delete Product

query {
  product(id: "123") {
    deleteApi
  }
}
Request:
fetch(product.deleteApi, {
  method: 'DELETE'
})

Add Product to Category

query {
  category(id: 5) {
    addProductUrl
  }
}

Remove Product from Category

query {
  product(id: "123") {
    removeFromCategoryUrl
  }
}

Add Variant to Product

query {
  product(id: "123") {
    variantGroup {
      addItemApi
    }
  }
}
Request:
fetch(variantGroup.addItemApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    product_id: 456,
    attributes: {
      color: 1,
      size: 2
    }
  })
})

Remove Variant

query {
  product(id: "123") {
    variantGroup {
      items {
        id
        removeUrl
      }
    }
  }
}
Request:
fetch(variant.removeUrl, {
  method: 'DELETE'
})

Category Management (Admin)

Update Category

query {
  category(id: 5) {
    updateApi
  }
}
Request:
fetch(category.updateApi, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'Updated Category',
    status: 1,
    include_in_nav: 1
  })
})

Delete Category

query {
  category(id: 5) {
    deleteApi
  }
}
Request:
fetch(category.deleteApi, {
  method: 'DELETE'
})

Order Management (Admin)

Create Shipment

query {
  order(uuid: "order-123") {
    createShipmentApi
  }
}
Request:
fetch(order.createShipmentApi, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    carrier: 'UPS',
    tracking_number: '1Z999AA10123456784'
  })
})

Update Shipment

query {
  order(uuid: "order-123") {
    shipment {
      updateShipmentApi
    }
  }
}
Request:
fetch(shipment.updateShipmentApi, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    tracking_number: '1Z999AA10123456999'
  })
})

Cancel Order

query {
  order(uuid: "order-123") {
    cancelApi
  }
}
Request:
fetch(order.cancelApi, {
  method: 'POST'
})

Customer Management (Admin)

Update Customer

query {
  customer(id: "customer-123") {
    updateApi
  }
}
Request:
fetch(customer.updateApi, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    full_name: 'John Smith',
    status: 1
  })
})

Delete Customer

query {
  customer(id: "customer-123") {
    deleteApi
  }
}
Request:
fetch(customer.deleteApi, {
  method: 'DELETE'
})

CMS Management (Admin)

Update CMS Page

query {
  cmsPage(id: 1) {
    updateApi
  }
}
Request:
fetch(cmsPage.updateApi, {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    name: 'Updated Page Title',
    content: '<p>New content</p>',
    status: 1
  })
})

Delete CMS Page

query {
  cmsPage(id: 1) {
    deleteApi
  }
}
Request:
fetch(cmsPage.deleteApi, {
  method: 'DELETE'
})

Best Practices

Always handle errors from API calls:
try {
  const response = await fetch(cart.addItemApi, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ product_id: 123, qty: 1 })
  })
  
  if (!response.ok) {
    const error = await response.json()
    console.error('Error:', error.message)
    return
  }
  
  const result = await response.json()
  // Handle success
} catch (error) {
  console.error('Network error:', error)
}
Include authentication credentials for authenticated requests:
fetch(api.url, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json'
  },
  credentials: 'include'  // Include cookies
})
Update UI optimistically before server response:
// Update UI immediately
setCartItems([...items, newItem])

// Then sync with server
try {
  await fetch(cart.addItemApi, { /* ... */ })
} catch (error) {
  // Rollback on error
  setCartItems(items)
}
Implement rate limiting for mutation requests:
import { debounce } from 'lodash'

const updateQty = debounce(async (api, qty) => {
  await fetch(api, {
    method: 'POST',
    body: JSON.stringify({ qty })
  })
}, 500)

Response Format

All API endpoints return JSON responses:

Success Response

{
  "success": true,
  "data": {
    // Updated entity data
  }
}

Error Response

{
  "success": false,
  "message": "Error description",
  "errors": [
    {
      "field": "qty",
      "message": "Quantity must be greater than 0"
    }
  ]
}

Next Steps

Queries

Explore available GraphQL queries

Types

View all GraphQL types and their fields

Build docs developers (and LLMs) love