Tutorial #2 - Modelling and Querying Complex Data

This post is part of our introduction series. In this tutorial you will learn how to model and query complex data with Quick.

You can find the commands and the schemas used for this tutorial in our quick-examples repository

In Quick you model stream data with data types and schemas. In our use-case we have a type Product that has fields productId, name, description, price and metadata. Because Price and Metadata are complex types, we take that into account in our GraphQL schema. Then we create a new topic with this schema definition.
type Product {
    productId: Int!,
    name: String,
    description: String,
    price: Price,
    metadata: Metadata
}

type Price {
    total: Float,
    currency: String
}

type Metadata {
    created_at: Int,
    source: String
}
> quick topic product-topic \
    --key long \
    --value schema --schema product-schema.gql
Created new topic product-topic
In this tutorial, we store product data in a JSON file and send an ingest request via curl.
{"key":123,"value":{"productId":123,"name":"T-Shirt","description":"black","price":{"total":19.99,"currency":"DOLLAR"},"metadata":{"created_at":1591710185,"source":"www.foo.com"}}}
> curl -X POST --url https://$QUICK_URL/ingest/product-topic \
    --header 'content-type: application/json' \
    --header 'X-API-Key: $KEY' \
    --data "@./products.json"
When we ingest data, we need to make sure our data matches the schema. This ensures integrity and consistency of data in Quick. When your data doesn't match the schema you will get an error.
{"key":456,"value":{"name":"T-Shirt","description":"black","price":19.99,"metadata":{"created_at":"2020-04-19T18:46:01+0000","source":"www.foo.com"}}}
> curl -X POST --url https://$QUICK_URL/ingest/product-topic \
    --header 'content-type: application/json' \
    --header 'X-API-Key: $KEY' \
    --data "@./invalid-product.json"
{"type":"errors/clientError","title":"Bad Request","code":400,"detail":"Data does not conform to schema: Could not ...
We define our queries, findProduct for finding a product by productId and allProducts to see all products in the product-topic. We also define the product schema and apply all to product-gateway.
type Query {
  findProduct(productId: Long): Product @topic(name: "product-topic", keyArgument: "productId")
  allProducts: [Product] @topic(name: "product-topic")
}

type Product {
  productId: Int!,
  name: String,
  description: String,
  price: Price,
  metadata: Metadata
}

type Price {
  total: Float,
  currency: String
}

type Metadata {
  created_at: Int,
  source: String
}
> quick gateway apply product-gateway -f schema.gql
Applied definition for gateway product-gateway
We query the stream data with GraphQL and get the response in JSON format.
query {
  allProducts {
    product {
      productId
      name
      price {
        total
        currency
      }
       metadata {
        created_at
        source
      }
    }
  }
}
{
  "data": {
    "allProducts": {
      "product": [
        {
          "productId": 123,
          "name": "T-Shirt",
          "price": {
            "total":  19.99,
            "currency": "DOLLAR"
          },
           "metadata": {
             "created_at": 1591710185,
             "source": "www.foo.com"
          }
        },
        {
          "productId": 456,
          "name": "Jeans",
          "price": {
            "total":  79.99,
            "currency": "EURO"
          }, ...
        }, ....
      ]
    }
  }
}