Browse Source

docs: Start graphql intro doc

Michael Bromley 2 years ago
parent
commit
2866738ddb

+ 1 - 1
docs/docs/guides/developer-guide/overview/index.md

@@ -14,7 +14,7 @@ These are the major parts of a Vendure application:
 * **Server**: The Vendure server is the part that handles requests coming in to the GraphQL APIs. It serves both the [Shop API](/reference/graphql-api/shop/queries) and [Admin API](/reference/graphql-api/admin/queries), and can send jobs to the Job Queue to be processed by the Worker.
 * **Worker**: The Worker runs in the background and deals with tasks such as updating the search index, sending emails, and other tasks which may be long-running, resource-intensive or require retries.
 * **Admin UI**: The Admin UI is how shop administrators manage orders, customers, products, settings and so on. It is not actually part of the Vendure core, but is provided as a plugin (the [AdminUiPlugin](reference/typescript-api/core-plugins/admin-ui-plugin/)) which is installed for you in a standard Vendure installation. The Admin UI can be further extended to support custom functionality, as detailed in the 
-* **Storefront**: With headless commerce, you are free to implement your storefront exactly as you see fit, unconstrained by the back-end, using any technologies that you like. To make this process easier, we have created a number of storefront starter kits, as well as [guides on building a storefront](/guides/storefront/building-a-storefront/).
+* **Storefront**: With headless commerce, you are free to implement your storefront exactly as you see fit, unconstrained by the back-end, using any technologies that you like. To make this process easier, we have created a number of [storefront starter kits](/guides/storefront/storefront-starters/), as well as [guides on building a storefront](/guides/storefront/connect-api/).
 
 ![./Vendure_docs-architecture.webp](./Vendure_docs-architecture.webp) 
 

+ 251 - 0
docs/docs/guides/getting-started/graphql-intro/index.mdx

@@ -0,0 +1,251 @@
+---
+title: Introducing GraphQL
+---
+import Playground from '@site/src/components/Playground';
+
+:::info
+This is an introduction to GraphQL for those who are new to it. If you are already familiar with GraphQL, you may choose
+to skip this section.
+:::
+
+## What is GraphQL?
+
+From [graphql.org](https://graphql.org/):
+
+> GraphQL is a query language for APIs and a runtime for fulfilling those queries with your existing data. GraphQL provides a complete and understandable description of the data in your API, gives clients the power to ask for exactly what they need and nothing more, makes it easier to evolve APIs over time, and enables powerful developer tools.
+
+To put it simply: GraphQL allows you to fetch data from an API via _queries_, and to update data via _mutations_.
+
+Here's a GraphQL query which fetches the product with the slug "football":
+
+<Playground api="shop" document={`
+query {
+  product(slug: "football") {
+    id
+    name
+    slug
+  }
+}
+`} />
+
+
+## GraphQL vs REST
+
+If you are familiar with REST-style APIs, you may be wondering how GraphQL differs from REST. Here are the key ways in which GraphQL differs from REST:
+
+- GraphQL uses **a single endpoint**, whereas REST uses a different endpoint for each resource.
+- GraphQL allows you to **specify exactly which fields** you want to fetch, whereas REST APIs usually all fields by default.
+- GraphQL allows you to fetch data from **multiple resources** in a single request (e.g. "fetch a customer including their last 5 orders"), whereas REST APIs usually require you to make multiple requests.
+- GraphQL APIs are always defined by a **statically typed schema**, whereas REST APIs do not have this guarantee.
+
+## Why GraphQL?
+
+Both GraphQL and REST are valid approaches to building an API. These are some of the reasons we chose GraphQL when building Vendure:
+
+- **No over-fetching**: With REST, you often end up fetching more data than you need. For example, if you want to fetch a list of products, you might end up fetching the product name, description, price, and other fields. With GraphQL, you can specify exactly which fields you want to fetch, so you only fetch the data you need. This
+    can result in a significant reduction in the amount of data transferred over the network.
+- **Many resources in a single request**: Very often, a single page in a web app will need to fetch data from multiple resources. For example, a product detail page might need to fetch the product, the product's variants, the product's collections, the product's reviews, and the product's images. With REST, this would require multiple requests. With GraphQL, you can fetch all of this data in a single request.
+- **Static typing**: GraphQL APIs are always defined by a statically typed schema. This means that you can be sure that the data you receive from the API will always be in the format you expect.
+- **Developer tooling**: The schema definition allows for powerful developer tooling. For example, the GraphQL Playground above with auto-complete and full documentation is generated automatically from the schema definition. You can also get auto-complete and type-checking directly in your IDE.
+- **Code generation**: TypeScript types can be generated automatically from the schema definition. This means that you can be sure that your frontend code is always in sync with the API. This end-to-end type safety is extremely valuable, especially when working on large projects or with teams.
+- **Extensible**: Vendure is designed with extensibility in mind, and GraphQL is a perfect fit. You can extend the GraphQL API with your own custom queries, mutations, and types. You can also extend the built-in types with your own custom fields, or supply you own custom logic to resolve existing fields.
+
+## GraphQL Terminology
+
+Let's clear up some of the terminology used in GraphQL.
+
+### Types & Fields
+
+GraphQL has a type system which works in a similar way to other statically typed languages like TypeScript.
+
+Here is an example of a GraphQL type:
+
+```graphql
+type Customer {
+  id: ID!
+  name: String!
+  email: String!
+}
+```
+
+The `Customer` is an **object type**, and it has three **fields**: `id`, `name`, and `email`. Each field has a **type** (e.g. `ID!` or `String!`), which
+can refer to either a **scalar type** (a "primitive" type which does not have any fields, but represents a single value) or another object type.
+
+GraphQL has a number of built-in scalar types, including `ID`, `String`, `Int`, `Float`, `Boolean`. Vendure further defines a few custom scalar types: `DateTime`, `JSON`, `Upload` & `Money`.
+It is also possible to define your own custom scalar types if required.
+
+The `!` symbol after the type name indicates that the field is **required** (it cannot be `null`). If a field does not have the `!` symbol, it is **optional** (it can be `null`).
+
+Here's another example of a couple of types:
+
+```graphql
+type Order {
+  id: ID!
+  orderPlacedAt: DateTime
+  isActive: Boolean!
+  customer: Customer!
+  lines: [OrderLine!]!
+}
+
+type OrderLine {
+  id: ID!
+  productId: ID!
+  quantity: Int!
+}
+```
+
+Here the `Order` type has a field called `customer` which is of type `Customer`. The `Order` type also has a field called `lines` which is an array of `OrderLine` objects.
+
+In GraphQL, lists are denoted by square brackets (`[]`). The `!` symbol inside the square brackets indicates that the list cannot contain `null` values.
+
+:::note
+The types given here are not the actual types used in the Vendure GraphQL schema, but are used here for illustrative purposes.
+:::
+
+### Query & Mutation types
+
+There are two special types in GraphQL: `Query` and `Mutation`. These are the entry points into the API.
+
+The `Query` type is used for fetching data, and the `Mutation` type is used for updating data.
+
+Here is an example of a query type:
+
+```graphql
+type Query {
+  customers: [Customer!]!
+}
+```
+
+This defines a `customers` field on the `Query` type. This field returns a list of `Customer` objects.
+
+Here's a mutation type:
+
+```graphql
+type Mutation {
+  updateCustomerName(customerId: ID!, name: String!): Customer!
+}
+```
+
+This defines a `updateCustomerName` field on the `Mutation` type. This field takes two arguments, `customerId` and `name`, and returns a `Customer` object.
+It would be used to update the name of the specified customer.
+
+### Input types
+
+Input types are used to pass complex (non-scalar) data to queries or mutations. For example, the `updateCustomerName` mutation above could be re-written
+to use an input type:
+
+```graphql
+type Mutation {
+  updateCustomerName(input: UpdateCustomerNameInput!): Customer!
+}
+
+input UpdateCustomerNameInput {
+  customerId: ID!
+  name: String!
+}
+```
+
+Input types look just like object types, but with the `input` keyword rather than `type`.
+
+### Schema
+
+The schema is the complete definition of the GraphQL API. It defines the types, fields, queries and mutations which are available.
+
+In a GraphQL API like Vendure, you can only query data according to the fields which are defined in the schema.
+
+Here is a complete, minimal schema:
+
+```graphql
+schema {
+  query: Query
+  mutation: Mutation
+}
+
+type Query {
+  customers: [Customer!]!
+}
+
+type Mutation {
+  updateCustomerName(input: UpdateCustomerNameInput!): Customer!
+}
+
+input UpdateCustomerNameInput {
+  customerId: ID!
+  name: String!
+}
+
+type Customer {
+  id: ID!
+  name: String!
+  email: String!
+}
+```
+
+The schema above tells you _everything_ that you can do with the API. You can fetch a list of customers, and you can update a customer's name.
+
+:::info
+The schema is one of the key benefits of GraphQL. It allows advanced tooling to be built around the API, such as autocomplete in IDEs, and
+automatic code generation.
+
+It also ensures that only valid queries can be made against the API.
+:::
+
+### Resolvers
+
+The schema defines the _shape_ of the data, but it does not define _how_ the data is fetched. This is the job of the resolvers.
+
+A resolver is a function which is responsible for fetching the data for a particular field. For example, the `customers` field on the `Query` type
+would be resolved by a function which fetches the list of customers from the database.
+
+To get started with Vendure's APIs, you don't need to know much about resolvers beyond this basic understanding. However,
+later on you may want to write your own custom resolvers to extend the API. This is covered in the [Extending the GraphQL API guide](/guides/how-to/extend-graphql-api/).
+
+:::info
+This is just a very brief overview. For a complete introduction to all parts of the GraphQL type system, see [Schemas & Types](https://graphql.org/learn/schema/)
+section of the official documentation.
+:::
+
+## Querying data
+
+Now that we have a basic understanding of the GraphQL type system, let's look at how we can use it to query data from the Vendure API.
+
+In REST terms, a GraphQL query is equivalent to a GET request. It is used to fetch data from the API. Queries should not change any
+data on the server.
+
+This is a GraphQL Playground running on a real Vendure server. You can run the query by clicking the "play" button in the
+middle of the two panes.
+
+<Playground api="shop" document={`
+query {
+  product(slug: "football") {
+    id
+    name
+    slug
+  }
+}
+`} />
+
+Let's get familiar with the schema:
+
+1. Hover your mouse over any field to see its type, and in the case of the `product` field itself, you'll see documentation about what it does.
+2. Add a new line after `slug` and press `Ctrl / ⌘` + `space` to see the available fields. At the bottom of the field list, you'll see the type of that field.
+3. Try adding the `description` field and press play. You should see the product's description in the response.
+4. Try adding `variants` to the field list. You'll see a red warning in the left edge, and hovering over `variants` will inform
+you that it must have a selection of subfields. This is because the `variants` field refers to an **object type**, so we must select
+which fields of that object type we want to fetch. For example:
+  ```graphql
+  query {
+    product(slug: "football") {
+      id
+      name
+      slug
+      variants {
+        sku
+        priceWithTax
+      }
+    }
+  }
+  ```
+
+
+

+ 5 - 2
docs/docs/guides/getting-started/installation/index.md

@@ -68,7 +68,8 @@ If you select MySQL, MariaDB or Postgres, you need to make sure you:
 The final prompt will ask whether to populate your new Vendure server with some sample product data.
 
 **We recommend you do so**, as it will give you a good starting point for exploring the APIs which we will cover 
-in the [next section](/guides/getting-started/first-steps/).
+in the [Try the API section](/guides/getting-started/try-the-api/), as well as providing some data to use when
+building your own storefront.
 
 ![Vendure Create step 2](./create-2.webp)
 
@@ -101,7 +102,9 @@ You should not be able to access:
 
 Congratulations! 🥳 You now have a fully-functional Vendure server running locally.
 
-Now you can explore Vendure by following our [Try The API guide](/guides/getting-started/first-steps/) to learn how to interact with the server.
+Now you can explore Vendure by following our [Try the API guide](/guides/getting-started/try-the-api/) to learn how to interact with the server.
+
+If you are new to GraphQL, you should also check out our [Introducing GraphQL guide](/guides/getting-started/graphql-intro/).
 
 :::tip
 Open the Admin UI at [http://localhost:3000/admin](http://localhost:3000/admin) in your browser and log in with the superadmin credentials you specified, which default to:

+ 20 - 19
docs/docs/guides/getting-started/first-steps/index.mdx → docs/docs/guides/getting-started/try-the-api/index.mdx

@@ -1,12 +1,16 @@
 ---
-title: "Try The API"
+title: "Try the API"
 ---
 
+import Playground from '@site/src/components/Playground';
+
 Once you have successfully installed Vendure locally following the [installation guide](/guides/getting-started/installation),
 it's time to try out the API!
 
 :::note
 This guide assumes you chose to populate sample data when installing Vendure.
+
+You can also follow along with these example using the public demo playground at [demo.vendure.io/shop-api](https://demo.vendure.io/shop-api)
 :::
 
 ## GraphQL Playground
@@ -39,7 +43,7 @@ Open the GraphQL Playground at [http://localhost:3000/shop-api](http://localhost
 
 Let's start with a **query**. Queries are used to fetch data. We will make a query to get a list of products.
 
-```graphql title="Shop API"
+<Playground api="shop" document={`
 query {
   products {
     totalItems
@@ -49,32 +53,31 @@ query {
     }
   }
 }
-```
+`} />
+
 
 Note that the response only includes the properties we asked for in our query (id and name). This is one of the key benefits
 of GraphQL - the client can specify exactly which data it needs, and the server will only return that data!
 
 Let's add a few more properties to the query:
 
-```graphql title="Shop API"
+<Playground api="shop" document={`
 query {
   products {
     totalItems
     items {
       id
       name
-      // highlight-start
       slug
       description
       featuredAsset {
         id
         preview
       }
-      // highlight-end
     }
   }
 }
-```
+`} />
 
 You should see that the response now includes the `slug`, `description` and `featuredAsset` properties. Note that the
 `featuredAsset` property is itself an object, and we can specify which properties of that object we want to include in the
@@ -84,9 +87,8 @@ want to include.
 Now let's add some arguments to the query. Some queries (and most mutations) can accept argument, which you put in parentheses
 after the query name. For example, let's fetch the first 5 products:
 
-```graphql title="Shop API"
+<Playground api="shop" document={`
 query {
-  // highlight-next-line
   products(options: { take: 5 }) {
     totalItems
     items {
@@ -95,17 +97,16 @@ query {
     }
   }
 }
-```
+`} />
 
 On running this query, you should see just the first 5 results being returned.
 
 Let's add a more complex argument: this time we'll filter for only those products which contain the string "shoe" in the
 name:
 
-```graphql title="Shop API"
+<Playground api="shop" document={`
 query {
   products(options: {
-    // highlight-next-line
     filter: { name: { contains: "shoe" } }
   }) {
     totalItems
@@ -115,7 +116,7 @@ query {
     }
   }
 }
-```
+`} />
 
 ### Add a product to an order
 
@@ -123,7 +124,7 @@ Next, let's look at a **mutation**. Mutations are used to modify data on the ser
 
 Here's a mutation which adds a product to an order:
 
-```graphql title="Shop API"
+<Playground api="shop" document={`
 mutation {
   addItemToOrder(productVariantId: 42, quantity: 1) {
     ...on Order {
@@ -145,7 +146,7 @@ mutation {
     }
   }
 }
-```
+`} />
 
 This mutation adds a product variant with ID `42` to the order. The response will either be an `Order` object, or an `ErrorResult`.
 We use a special syntax called a **fragment** to specify which properties we want to include in the response. In this case,
@@ -170,7 +171,7 @@ Open the GraphQL Playground at [http://localhost:3000/admin-api](http://localhos
 
 Most Admin API operations are restricted to authenticated users. So first of all we'll need to log in.
 
-```graphql title="Admin API"
+<Playground api="admin" server="demo" document={`
 mutation {
   login(username: "superadmin", password: "superadmin") {
     ...on CurrentUser {
@@ -183,13 +184,13 @@ mutation {
     }
   }
 }
-```
+`} />
 
 ### Fetch a product
 
 The Admin API exposes a lot more information about products than you can get from the Shop API:
 
-```graphql title="Admin API"
+<Playground api="admin" server="demo" document={`
 query {
   product(id: 42) {
     enabled
@@ -210,7 +211,7 @@ query {
     }
   }
 }
-```
+`} />
 
 :::info
 GraphQL is statically typed and uses a **schema** containing information about all the available queries, mutations and types. In the

+ 0 - 0
docs/docs/guides/getting-started/first-steps/playground-docs.webp → docs/docs/guides/getting-started/try-the-api/playground-docs.webp


+ 0 - 0
docs/docs/guides/getting-started/first-steps/playground-setup.webp → docs/docs/guides/getting-started/try-the-api/playground-setup.webp


+ 0 - 0
docs/docs/guides/getting-started/first-steps/playground.webp → docs/docs/guides/getting-started/try-the-api/playground.webp


+ 2 - 0
docs/docs/guides/storefront/navigation-menu/index.mdx

@@ -150,6 +150,8 @@ export function arrayToTree<T extends HasParent>(nodes: T[]): RootNode<T> {
 }
 ```
 
+## Live example
+
 Here's a live demo of the above code in action:
 
 <Stackblitz id='vendure-docs-collection-tree' />

+ 7 - 2
docs/docs/guides/storefront/product-detail/index.mdx

@@ -223,11 +223,16 @@ fragment UpdatedOrder on Order {
   state
   totalQuantity
   totalWithTax
+  currencyCode
   lines {
     id
     unitPriceWithTax
     quantity
     linePriceWithTax
+    productVariant {
+      id
+      name
+    }
   }
 }
 ```
@@ -273,7 +278,7 @@ fragment UpdatedOrder on Order {
 
 There are some important things to note about this mutation:
 
-- Because the `addItemToOrder` mutation returns a union type, we need to use a [fragment](/guides/core-concepts/graphql/#fragments) to specify the fields we want to return.
+- Because the `addItemToOrder` mutation returns a union type, we need to use a [fragment](/TODO) to specify the fields we want to return.
 In this case we have defined a fragment called `UpdatedOrder` which contains the fields we are interested in.
 - If any [expected errors](/guides/advanced-topics/error-handling) occur, the mutation will return an `ErrorResult` object. We'll be able to
 see the `errorCode` and `message` fields in the response, so that we can display a meaningful error message to the user.
@@ -287,4 +292,4 @@ of the returned type. This means that we can check whether `__typename === 'Orde
 
 Here's an example that brings together all of the above concepts:
 
-<Stackblitz id="vendure-docs-product-detail-page" />
+<Stackblitz id="vendure-docs-product-detail" />

+ 5 - 1
docs/sidebars.js

@@ -31,7 +31,11 @@ const sidebars = {
         {
             type: 'category',
             label: 'Getting Started',
-            items: ['guides/getting-started/installation/index', 'guides/getting-started/first-steps/index'],
+            items: [
+                'guides/getting-started/installation/index',
+                'guides/getting-started/graphql-intro/index',
+                'guides/getting-started/try-the-api/index',
+            ],
             customProps: {
                 icon: icon.bolt,
             },

+ 19 - 0
docs/src/components/Playground/index.tsx

@@ -0,0 +1,19 @@
+import React from 'react';
+
+export default function Playground(props: {
+    document: string;
+    api: 'shop' | 'admin';
+    server: 'readonlydemo' | 'demo';
+}) {
+    const urlEncoded = encodeURIComponent(props.document.trim());
+    return (
+        <iframe
+            style={{
+                width: '100%',
+                minHeight: '500px',
+                borderRadius: '8px',
+            }}
+            src={`https://${props.server ?? 'readonlydemo'}.vendure.io/${props.api}-api?query=${urlEncoded}`}
+        />
+    );
+}

+ 1 - 0
docs/src/components/Stackblitz/index.tsx

@@ -6,6 +6,7 @@ export default function Stackblitz(props: { id: string }) {
             style={{
                 width: '100%',
                 minHeight: '500px',
+                borderRadius: '8px',
             }}
             src={`https://stackblitz.com/edit/${props.id}?ctl=1&embed=1`}
         />