Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: move each operator + helpers to /operators folder #58

782 changes: 0 additions & 782 deletions docs/guides/operators.md

This file was deleted.

87 changes: 87 additions & 0 deletions docs/guides/operators/add-field.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
---
title: "@addField"
sidebar_position: 6
---

The `@addField` operator simplifies data structures and queries by adding a field that _inlines_ or flattens a nested field or node within your schema. It works by modifying the schema and the data transformation process, simplifying how nested data is accessed and presented.

For instance, consider a schema:

```graphql showLineNumbers
schema {
query: Query
}

type User @addField(name: "street", path: ["address", "street"]) {
id: Int!
name: String!
username: String!
email: String!
phone: String
website: String
address: Address @modify(omit: true)
}

type Address {
street: String!
city: String!
state: String!
}

type Query {
user(id: Int!): User @http(path: "/users/{{args.id}}")
}
```

Suppose we are only interested in the `street` field in `Address`.

The `@addField` operator above, applied to the `User` type in this case, creates a field called `street` in the `User` type. It includes a `path` argument, indicating the chain of fields to be traversed from a declared field (`address` in this case), to the field within Address to be added. We can also add a `@modify(omit: true)` to omit the `address` field from the schema, since we have already made its `street` field available on the `User` type.

Post application, the schema becomes:

```graphql showLineNumbers
schema {
query: Query
}

type User {
id: Int!
name: String!
username: String!
email: String!
phone: String
website: String
street: String
}

type Query {
user(id: Int): Post!
}
```

In the above example, since we added a `@modify(omit: true)` on the `address` field, the `Address` type is eliminated from the schema.

The `@addField` operator also take cares of nullablity of the fields. If any of the fields in the path is nullable, the resulting type will be nullable.

Additionally, `@addField` supports indexing, meaning you can specify the array index to be inlined. If a field `posts` is of type `[Post]`, and you want to, for example, get the title of the first post, you can specify the path as [`"posts"`,`"0"`,`"title"`].

```graphql showLineNumbers
type User @addField(name: "firstPostTitle", path: ["posts", "0", "title"]) {
id: Int!
name: String!
username: String!
email: String!
phone: String
website: String
posts: Post @http(path: "/users/{{value.id}}/posts")
}

type Post {
id: Int!
userId: Int!
title: String!
body: String!
}
```

In conclusion, the `@addField` operator helps tidy up your schema and streamline data fetching by reducing query depth, promoting better performance and simplicity.
23 changes: 23 additions & 0 deletions docs/guides/operators/const.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: "@const"
sidebar_position: 7
---

The `@const` operators allows us to embed a constant response for the schema. For eg:

```graphql
schema {
query: Query
}

type Query {
user: User @const(data: {name: "John", age: 12})
}

type User {
name: String
age: Int
}
```

The const operator will also validate the provided value at compile time to make sure that it matches the of the field. If the schema of the provided value doesn't match the type of the field, a descriptive error message is show on the console.
112 changes: 112 additions & 0 deletions docs/guides/operators/graphql.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
title: "@graphQL"
sidebar_position: 4
---

## @graphQL

The **@graphQL** operator allows to specify GraphQL API server request to fetch data from.

```graphql showLineNumbers
type Query {
users: [User] @graphQL(name: "userList")
}
```

In this example, the `@graphQL` operator is used to fetch list of users from the GraphQL API upstream. The [name](#name) argument is used to specify the name of the root field on the upstream server. The inner fields from the `User` type to request are inferred from the upcoming request to the Tailcall server. The operation type of the query is inferred from the Tailcall config based on inside which operation type the `@graphQL` operator is used.

For next request with the config above:

```graphql showLineNumbers
query {
users {
id
name
}
}
```

Tailcall will request next query for the upstream:

```graphql showLineNumbers
query {
userList {
id
name
}
}
```

### baseURL

This refers to the base URL of the API. If not specified, the default base URL is the one specified in the [@upstream](#upstream) operator.

```graphql showLineNumbers
type Query {
users: [User] @graphQL(name: "users", baseURL: "https://graphqlzero.almansi.me/api")
}
```

### name

Name of the root field on the upstream to request data from. For example:

```graphql showLineNumbers
type Query {
users: [User] @graphQL(name: "userList")
}
```

When Tailcall receives query for `users` field it will request query for `userList` from the upstream.

### args

Named arguments for the requested field. For example:

```graphql showLineNumbers
type Query {
user: User @graphQL(name: "user", args: [{key: "id", value: "{{value.userId}}"}])
}
```

Will request next query from the upstream for first user's name:

```graphql showLineNumbers
query {
user(id: 1) {
name
}
}
```

### headers

The `headers` parameter allows you to customize the headers of the GraphQL request made by the `@graphQL` operator. It is used by specifying a key-value map of header names and their values.

For instance:

```graphql showLineNumbers
type Mutation {
users: User @graphQL(name: "users", headers: [{key: "X-Server", value: "Tailcall"}])
}
```

In this example, a request to `/users` will include an additional HTTP header `X-Server` with the value `Tailcall`.

### batch

In case upstream GraphQL server supports request batching we can specify argument `batch` to batch several requests to single upstream into single batch request. For example:

```graphql showLineNumbers
schema @upstream(batch: {maxSize: 1000, delay: 10, headers: ["X-Server", "Authorization"]}) {
query: Query
mutation: Mutation
}

type Query {
users: [User] @graphQL(name: "users", batch: true)
posts: [Post] @graphQL(name: "posts", batch: true)
}
```

Make sure you have also specified batch settings to the `@upstream` and to the `@graphQL` operator.
117 changes: 117 additions & 0 deletions docs/guides/operators/http.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
---
title: "@http"
sidebar_position: 3
---

This **@http** operator serves as an indication of a field or node that is underpinned by a REST API. For Example:

```graphql showLineNumbers
type Query {
users: [User] @http(path: "/users")
}
```

In this example, the `@http` operator is added to the `users` field of the `Query` type. This means that the `users` field is underpinned by a REST API. The [path](#path) argument is used to specify the path of the REST API. In this case, the path is `/users`. This means that the GraphQL server will make a GET request to `https://jsonplaceholder.typicode.com/users` when the `users` field is queried.

## baseURL

This refers to the base URL of the API. If not specified, the default base URL is the one specified in the [@upstream](#upstream) operator.

```graphql showLineNumbers
type Query {
users: [User] @http(path: "/users", baseURL: "https://jsonplaceholder.typicode.com")
}
```

## path

This refers to the API endpoint you're going to call. For instance https://jsonplaceholder.typicode.com/users`.

```graphql showLineNumbers
type Query {
users: [User] @http(path: "/users")
}
```

If your API endpoint contains dynamic segments, you can use Mustache templates to substitute variables. For example, to fetch a specific user, the path can be written as `/users/{{args.id}}`.

```graphql showLineNumbers
type Query {
user(id: ID!): User @http(path: "/users/{{args.id}}")
}
```

## method

This refers to the HTTP method of the API call. Commonly used methods include GET, POST, PUT, DELETE, etc. If not specified, the default method is GET. For example:

```graphql showLineNumbers
type Mutation {
createUser(input: UserInput!): User @http(method: "POST", path: "/users")
}
```

## query

This represents the query parameters of your API call. You can pass it as a static object or use Mustache template for dynamic parameters. These parameters will be added to the URL. For example:

```graphql showLineNumbers
type Query {
userPosts(id: ID!): [Post] @http(path: "/posts", query: [{key: "userId", value: "{{args.id}}"}])
}
```

## body

The body of the API call. It's used for methods like POST or PUT that send data to the server. You can pass it as a static object or use a Mustache template to substitute variables from the GraphQL variables. For example:

```graphql showLineNumbers
type Mutation {
createUser(input: UserInput!): User @http(method: "POST", path: "/users", body: "{{args.input}}")
}
```

In the example above, the `createUser` mutation sends a POST request to `/users`, with the input object converted to JSON and included in the request body.

## headers

The `headers` parameter allows you to customize the headers of the HTTP request made by the `@http` operator. It is used by specifying a key-value map of header names and their values.

For instance:

```graphql showLineNumbers
type Mutation {
createUser(input: UserInput!): User @http(path: "/users", headers: [{key: "X-Server", value: "Tailcall"}])
}
```

In this example, a request to `/users` will include an additional HTTP header `X-Server` with the value `Tailcall`.

You can make use of mustache templates to provide dynamic values for headers, derived from the arguments or [context] provided in the request. For example:

[context]: /docs/guides/context

```graphql showLineNumbers
type Mutation {
users(name: String): User
@http(path: "/users", headers: [{key: "X-Server", value: "Tailcall"}, {key: "User-Name", value: "{{args.name}}"}])
}
```

In this scenario, the `User-Name` header's value will dynamically adjust according to the `name` argument passed in the request.

## groupBy

The `groupBy` parameter groups multiple data requests into a single call. For more details please refer out [n + 1 guide].

[n + 1 guide]: /docs/guides/n+1#solving-using-batching

```graphql showLineNumbers
type Post {
id: Int!
name: String!
user: User @http(path: "/users", query: [{key: "id", value: "{{value.userId}}"}], groupBy: ["id"])
}
```

- `query: {key: "id", value: "{{value.userId}}"}]`: Here, TailCall CLI is instructed to generate a URL where the user id aligns with the `userId` from the parent `Post`. For a batch of posts, the CLI compiles a single URL, such as `/users?id=1&id=2&id=3...id=10`, consolidating multiple requests into one.
10 changes: 8 additions & 2 deletions docs/guides/composition.md → docs/guides/operators/index.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
---
title: Operator Composition
sidebar_position: 2
title: "Operators"
sidebar_position: 1
---

Tailcall DSL builds on your existing GraphQL knowledge by allowing the addition of some custom operators. These operators provide powerful compile time guarantees to make sure your API composition is tight and robust. The operator information is used to automatically generates highly optimized resolver logic for your types.

# Composition

Operators can be composed and used together to create new and powerful transformations.

This example illustrates the concept of composition in GraphQL, which allows you to combine multiple operations (known as "operators") to build more complex transformations of data.

The given schema is defining two data types - `User` and `Post`. The `User` type has fields `id` and `name`, and the `Post` type initially has fields `user` and `userId`.
Expand Down
30 changes: 30 additions & 0 deletions docs/guides/operators/modify.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: "@modify"
sidebar_position: 5
---

The `@modify` operator in GraphQL provides the flexibility to alter the attributes of a field or a node within your GraphQL schema. Here's how you can use this operator:

## name

You can rename a field or a node in your GraphQL schema using the `name` argument in the `@modify` operator. This can be helpful when the field name in your underlying data source doesn't match the desired field name in your schema. For instance:

```graphql showLineNumbers
type User {
id: Int! @modify(name: "userId")
}
```

`@modify(name: "userId")` tells GraphQL that although the field is referred to as `id`in the underlying data source, it should be presented as `userId` in your schema.

## omit

You can exclude a field or a node from your GraphQL schema using the `omit` argument in the `@modify` operator. This can be useful if you want to keep certain data hidden from the client. For instance:

```graphql showLineNumbers
type User {
id: Int! @modify(omit: true)
}
```

`@modify(omit: true)` tells GraphQL that the `id` field should not be included in the schema, thus it won't be accessible to the client.
Loading
Loading