Command Line Reference
The Tailcall CLI (Command Line Interface) allows developers to manage and optimize GraphQL configurations directly from the command line.
check
The check
command validates a composition spec. Notably, this command can detect potential N+1 issues. To use the check
command, follow this format:
tailcall check [OPTIONS] <FILE_PATHS>...
The check
command offers options that control settings such as the display of the generated schema, n + 1 issues etc.
--n-plus-one-queries
This flag triggers the detection of N+1 issues.
- Type: Boolean
- Default: false
tailcall check --n-plus-one-queries <FILE_PATHS> ...
--schema
This option enables the display of the schema of the composition spec.
- Type: Boolean
- Default: false
tailcall check --schema <file1> <file2> ... <fileN>
The check
command allows for files. Specify each file path, separated by a space, after the options.
Example:
tailcall check --schema ./path/to/file1.graphql ./path/to/file2.graphql
--verify-ssl
Controls SSL/TLS certificate verification when loading remote configuration files.
- Type: Boolean
- Default:
true
tailcall check --verify-ssl false < FILE_PATHS > ...
Disabling SSL verification is not recommended for production environments as it makes your connections vulnerable to man-in-the-middle attacks.
start
The start
command launches the GraphQL Server for the specific configuration.
To start the server, use the following command:
tailcall start <file1> <file2> ... <fileN> <http_path1> <http_path2> .. <http_pathN>
The start
command allows for files and supports loading configurations over HTTP. You can mix file system paths with HTTP paths. Specify each path, separated by a space, after the options.
Example:
tailcall start ./path/to/file1.graphql ./path/to/file2.graphql http://example.com/file2.graphql
--verify-ssl
Controls SSL/TLS certificate verification when loading remote configuration files.
- Type: Boolean
- Default:
true
tailcall start --verify-ssl false < FILE_PATHS > ...
Disabling SSL verification is not recommended for production environments as it makes your connections vulnerable to man-in-the-middle attacks.
init
The init
command bootstraps a new Tailcall project. It creates the necessary GraphQL schema files in the provided file path.
tailcall init <file_path>
This command prompts for file creation and configuration, creating the following files:
File Name | Description |
---|
| .graphqlrc.yml | An IDE configuration that references your GraphQL schema and the following .tailcallrc.graphql
. |
| .tailcallrc.graphql | Contains Tailcall specific auto-completions for .graphql
format. |
gen
The gen
command in the Tailcall CLI is designed to generate GraphQL configurations from various sources, such as protobuf files and REST endpoints.
usage:
tailcall gen path_to_configuration_file.json
To generate a Tailcall GraphQL configuration, provide a configuration file to the gen
command like done above. This configuration file should be in JSON or YAML format, as illustrated in the example below:
- JSON
- YML
{
"llm": {
"model": "gemini-1.5-flash-latest",
"secret": "API_KEY"
},
"inputs": [
{
"curl": {
"src": "https://jsonplaceholder.typicode.com/posts/1",
"fieldName": "post",
"headers": {
"Content-Type": "application/json",
"Accept": "application/json",
"Authorization": "Bearer {{.env.AUTH_TOKEN}}"
}
}
},
{
"curl": {
"src": "https://jsonplaceholder.typicode.com/posts",
"method": "POST",
"body": {
"title": "Tailcall - Modern GraphQL Runtime",
"body": "Tailcall - Modern GraphQL Runtime",
"userId": 1
},
"headers": {
"Content-Type": "application/json",
"Accept": "application/json"
},
"isMutation": true,
"fieldName": "createPost"
}
},
{
"proto": {
"src": "./news.proto",
"url": "http://127.0.0.1:8080/rpc"
}
}
],
"output": {
"path": "./output.graphql"
},
"schema": {
"query": "Query",
"mutation": "Mutation"
},
"preset": {
"mergeType": 1,
"treeShake": true,
"unwrapSingleFieldTypes": true,
"inferTypeNames": true
}
}
llm:
model: "gemini-1.5-flash-latest"
secret: "API_KEY"
inputs:
- curl:
src: "https://jsonplaceholder.typicode.com/posts/1"
fieldName: "post"
headers:
Content-Type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{.env.AUTH_TOKEN}}"
- curl:
src: "https://jsonplaceholder.typicode.com/posts"
method: "POST"
body:
title: "Tailcall - Modern GraphQL Runtime"
body: "Tailcall - Modern GraphQL Runtime"
userId: 1
headers:
Content-Type: "application/json"
Accept: "application/json"
isMutation: true
fieldName: "createPost"
- proto:
src: "./news.proto"
url: "http://127.0.0.1:8080/rpc"
output:
path: "./output.graphql"
schema:
query: "Query"
mutation: "Mutation"
preset:
mergeType: 1
treeShake: true
unwrapSingleFieldTypes: true
inferTypeNames: true
Inputs
The inputs
section specifies the sources from which the GraphQL configuration should be generated. Each source can be either a REST endpoint or a protobuf file.
-
REST: When defining REST endpoints, the configuration should include the following properties.
-
src (Required): The URL of the REST endpoint. In this example, it points to a specific post on
jsonplaceholder.typicode.com
. -
fieldName (Required): A unique name that should be used as the field name, which is then used in the operation type. In the example below, it's set to
post
.importantEnsure that each field name is unique across the entire configuration to prevent overwriting previous definitions.
-
headers (Optional): Users can specify the required headers to make the HTTP request in the headers section.
infoEnsure that secrets are not stored directly in the configuration file. Instead, use templates to securely reference secrets from environment variables. For example, see the following configuration where AUTH_TOKEN is referenced from the environment like
{{.env.AUTH_TOKEN}}
. -
body (Optional): This property allows you to specify the request body for methods like POST or PUT. If the endpoint requires a payload, include it here.
-
method (Optional): Specify the HTTP method for the request (e.g. GET, POST, PUT, DEL). If not provided, the default method is
GET
. -
isMutation (Optional): This flag indicates whether the request should be treated as a GraphQL Mutation. Set
isMutation
totrue
to configure the request as aMutation
. If not specified or set to false, the request will be treated as aQuery by default
.
-
-
Query Operation: To define a GraphQL Query, either omit the isMutation property or set it to false. By default, if isMutation is not provided, the request will be configured as a Query.
- JSON
- YML
sample input example for generating Query typesample input example for generating Query type{
"curl": {
"src": "https://jsonplaceholder.typicode.com/posts/1",
"fieldName": "post",
"headers": {
"Authorization": "Bearer {{.env.AUTH_TOKEN}}"
}
}
}sample input example for generating Query typesample input example for generating Query type- curl:
src: "https://jsonplaceholder.typicode.com/posts/1"
fieldName: "post"
headers:
Content-Type: "application/json"
Accept: "application/json"
Authorization: "Bearer {{.env.AUTH_TOKEN}}"For the above input configuration, the following field will be generated in the operation type:
Generated ConfigurationGenerated Configurationtype Query {
# field name is taken from the above JSON config
post(p1: Int!): Post
@http(
url: "https://jsonplaceholder.typicode.com/posts/{{arg.p1}}"
)
} -
Mutation Operation: To define a GraphQL Mutation, set
isMutation
totrue
and provide the necessaryrequest body, method, isMutation and headers.
- JSON
- YML
sample input example for generating Mutation typesample input example for generating Mutation type{
"curl": {
"src": "https://jsonplaceholder.typicode.com/posts",
"method": "POST",
"body": {
"title": "Tailcall - Modern GraphQL Runtime",
"body": "Tailcall - Modern GraphQL Runtime",
"userId": 1
},
"headers": {
"Content-Type": "application/json",
"Accept": "application/json"
},
"isMutation": true,
"fieldName": "createPost"
}
}sample input example for generating Mutation typesample input example for generating Mutation type- curl:
src: "https://jsonplaceholder.typicode.com/posts"
method: "POST"
body:
title: "Tailcall - Modern GraphQL Runtime"
body: "Tailcall - Modern GraphQL Runtime"
userId: 1
headers:
Content-Type: "application/json"
Accept: "application/json"
isMutation: true
fieldName: "createPost"For the above input configuration, the following field will be generated in the operation type:
Generated ConfigurationGenerated Configurationinput PostInput {
title: String
body: String
userId: ID
}
type Mutation {
# field name is taken from the above JSON config
createPost(createPostInput: PostInput!): Post
@http(
url: "https://jsonplaceholder.typicode.com/posts/{{arg.p1}}"
method: "POST"
)
} -
Proto:
-
Specify the path to the proto file (
src
) to help Tailcall create a schema and understand the gRPC methods to call when a field is queried. -
Specify the gRPC URL (
url
) where the gRPC service is hosted. -
Include a boolean parameter
connectRPC
(optional). If set totrue
, the proto file will be used to generate the schema, but the communication between Tailcall and the upstream will happen using the Connect-RPC protocol. -
Specify a set of directories
protoPaths
(optional) to search for imported proto files. Works like the--proto_path
flag in the protocol compiler.- JSON
- YML
{
"proto": {
"src": "./path/to/file.proto",
"url": "http://127.0.0.1:8080/rpc"
}
}- proto:
src: "./news.proto"
url: "http://127.0.0.1:8080/rpc"
-
Output
The output
section specifies the path for the generated GraphQL configuration.
- path: The file path where the output will be saved.
Preset
The config generator provides a set of tuning parameters that can make the generated configurations more readable by reducing duplication. This can be configured using the preset
section.
- JSON
- YML
{
"preset": {
"mergeType": 1,
"treeShake": true,
"unwrapSingleFieldTypes": true,
"inferTypeNames": true
}
}
preset:
mergeType: 1
treeShake: true
unwrapSingleFieldTypes: true
inferTypeNames: true
-
mergeType: This setting merges types in the configuration that satisfy the threshold criteria. It takes a threshold value between
0.0
and1.0
to determine if two types should be merged or not. The default is1.0
.For example, the following types
T1
andT2
are exactly similar, and with a threshold value of1.0
, they can be merged into a single type calledM1
:Merging type T1 and T2 into M1Merging type T1 and T2 into M1# BEFORE
type T1 {
id: ID
firstName: String
lastName: String
}
type T2 {
id: ID
firstName: String
lastName: String
}
# AFTER: T1 and T2 are merged into M1.
type M1 {
id: ID
firstName: String
lastName: String
} -
treeShake: This setting removes unused types from the configuration. When enabled, any type that is defined in the configuration but not referenced anywhere else (e.g., as a field type, union member, or interface implementation) will be removed. This helps to keep the configuration clean and free from unnecessary definitions.
Before applying treeShake, the configuration might look like this.Before applying treeShake, the configuration might look like this.type Query {
foo: Foo
}
type Foo {
bar: Bar
}
# Type not used anywhere else
type UnusedType {
baz: String
}
type Bar {
a: Int
}After enabling treeShake, the UnusedType will be removed.After enabling treeShake, the UnusedType will be removed.type Query {
foo: Foo
}
type Foo {
bar: Bar
}
type Bar {
a: Int
} -
unwrapSingleFieldTypes: This setting instructs Tailcall to flatten out types with single field.
Before applying the settingBefore applying the settingtype Query {
foo: Foo
}
# Type with only one field
type Foo {
bar: Bar
}
# Type with only one field
type Bar {
a: Int
}After applying settingAfter applying settingtype Query {
foo: Int
}This helps in flattening out types into single field.
-
inferTypeNames: This setting enables the automatic inference of type names based on their schema and it's usage. For it to work reliably it depends on an external secure AI agent.
Before enabling inferTypeNames settingBefore enabling inferTypeNames settingtype T1 {
id: ID
name: String
email: String
post: [T2]
}
type T2 {
id: ID
title: String
body: String
}
type Query {
users: [T1]
@http(
url: "https://jsonplaceholder.typicode.com/users"
)
}-
Type T1: T1 is used as the output type for the
user
field in the Query type. We recognize that T1 is associated with users in the users field of Query. Therefore, it infers that T1 should be namedUser
to indicate that it represents user data. -
Type T2: T2 is used as the output type for the
post
field within T1. We recognize that T2 is associated with posts in the post field of User. Therefore, it infers that T2 should be namedPost
to indicate that it represents post data.
After enabling inferTypeNames settingAfter enabling inferTypeNames settingtype User {
id: ID
name: String
email: String
post: [Post]
}
type Post {
id: ID
title: String
body: String
}
type Query {
user: User
@http(
url: "https://jsonplaceholder.typicode.com/users"
)
}By leveraging field names to derive type names, the schema becomes more intuitive and aligned with the data it represents, enhancing overall readability and understanding. You can learn more about config autogen here.
-
LLM
Tailcall leverages LLM to improve the quality of configuration files by suggesting better names for types, fields, and more. The llm
section in the configuration allows you to specify the LLM model and secret (API key) that will be used for generating the configuration.
Example:
-
Using Gemini. Set TAILCALL_LLM_API_KEY to your Gemini API key.
"llm": {
"model": "gemini-1.5-flash-latest",
"secret": "{{.env.TAILCALL_LLM_API_KEY}}"
} -
Using Ollama. Don't need secret.
"llm": {
"model": "gemma2",
}
Ensure that secrets are not stored directly in the configuration file. Instead, use templates to securely reference secrets from environment variables. For example, you can write secret as {{.env.TAILCALL_SECRET}}
, where TAILCALL_SECRET
is referenced from the running environment.