@server
The @server
directive is defined as follows:
directive @server(
workers: Int
port: Int
headers: ServerHeaders
introspection: Boolean
queryValidation: Boolean
responseValidation: Boolean
globalResponseTimeout: Int
version: Version
cert: String
key: String
showcase: Boolean
batchRequests: Boolean
routes: Routes
enableFederation: Boolean
vars: [InputKeyValue!]
) on SCHEMA
input ServerHeaders {
cacheControl: Boolean
custom: [InputKeyValue!]
experimental: [String!]
setCookies: Boolean
cors: CorsConfig
}
input CorsConfig {
allowCredentials: Boolean
allowHeaders: [String!]
allowMethods: [Method!]
allowOrigins: [String!]
allowPrivateNetwork: Boolean
exposeHeaders: [String!]
maxAge: Int
vary: [String!]
}
input Routes {
graphQL: String
status: String
}
enum Version {
HTTP1
HTTP2
}
The @server
directive, applied at the schema level, provides a comprehensive set of server configurations. It dictates server behavior and helps tune Tailcall for a range of use-cases.
schema @server(...[ServerSettings]...){
query: Query
mutation: Mutation
}
In this templated structure, replace ...[ServerSettings]...
with specific configurations tailored to your project's needs. Adjust and expand these settings as necessary.
The ServerSettings
options and their details appear below.
workers
Setting workers
to 32
means that the GraphQL server will use 32 worker threads.
schema @server(workers: 32) {
query: Query
mutation: Mutation
}
This example sets the workers
to 32
, meaning the GraphQL server will use 32 worker threads.
port
Setting the port
to 8090
means that Tailcall will be accessible at http://localhost:8000
.
schema @server(port: 8090) {
query: Query
mutation: Mutation
}
This example sets the port
to 8090
, making Tailcall accessible at http://localhost:8090
.
Always choose non-standard ports, avoiding typical ones like 80 or 8080. Make sure your chosen port is free.
headers
Allows intelligent configuration of the final response headers that's produced by Tailcall.
cacheControl
Activating the cacheControl
configuration directs Tailcall to send Cache-Control headers in its responses. The max-age
value in the header matches the lowest of the values in the responses that Tailcall receives from its upstream. By default, this is false
, which means Tailcall does not set any header.
schema @server(headers: {cacheControl: true}) {
query: Query
mutation: Mutation
}
custom
The custom
is an array of key-value pairs. These headers get added to the response of every request made to the server. This can be useful for adding headers like Access-Control-Allow-Origin
to allow cross-origin requests, or some headers like X-Allowed-Roles
for use by downstream services.
schema
@server(
headers: {
custom: [
{key: "X-Allowed-Roles", value: "admin,user"}
]
}
) {
query: Query
mutation: Mutation
}
experimental
When the experimental
configuration is enabled, Tailcall can include headers starting with X-
in its responses, which are sourced from its upstream. By default, this feature is disabled ([]
), meaning Tailcall does not forward any such headers unless explicitly configured to do so.
schema
@server(
headers: {experimental: ["X-Experimental-Header"]}
) {
query: Query
mutation: Mutation
}
setCookies
Enabling the setCookies
option instructs Tailcall to include set-cookie
headers in its responses, which are obtained from the headers of upstream responses.
schema @server(headers: {setCookies: true}) {
query: Query
mutation: Mutation
}
cors
The cors
configuration allows you to enable CORS on Tailcall. This is useful when you want to access Tailcall in the browser. Here is a simple configuration to get started with cors:
schema
@server(
headers: {
cors: {allowHeaders: ["*"], allowOrigins: ["*"]}
}
) {
query: Query
}
The above setting will enable CORS on the server for all headers, origins & methods. You can further configure the cors settings to make it more secure with the following fields:
allowCredentials
: Indicates whether the server allows credentials (e.g., cookies, authorization headers) to be sent in cross-origin requests.allowHeaders
: A list of allowed headers in cross-origin requests. This can be used to specify custom headers that are allowed to be included in cross-origin requests.allowMethods
: A list of allowed HTTP methods in cross-origin requests. These methods specify the actions that are permitted in cross-origin requests.allowOrigins
: A list of origins that are allowed to access the server's resources in cross-origin requests. An origin can be a domain, a subdomain, or even 'null' for local file schemes.allowPrivateNetwork
: Indicates whether requests from private network addresses are allowed in cross-origin requests. Private network addresses typically include IP addresses reserved for internal networks.exposeHeaders
: A list of headers that the server exposes to the browser in cross-origin responses. Exposing certain headers allows client-side code to access them in the response.maxAge
: The maximum time (in seconds) that the client should cache preflight OPTIONS requests to avoid sending excessive requests to the server.vary
: A list of header names that indicate the values of which might cause the server's response to vary, potentially affecting caching.
schema
@server(
port: 8000
hostname: "0.0.0.0"
headers: {
cors: {
allowCredentials: false
allowHeaders: ["Authorization"]
allowMethods: [POST, GET, OPTIONS]
allowOrigins: ["abc.xyz"]
allowPrivateNetwork: true
exposeHeaders: ["Content-Type"]
maxAge: 360
vary: ["Origin"]
}
}
) {
query: Query
}
vars
This configuration allows defining local variables for use during the server's operations. These variables are handy for storing constant configurations, secrets, or other shared information that operations might need.
schema
@server(
vars: {key: "apiKey", value: "YOUR_API_KEY_HERE"}
) {
query: Query
mutation: Mutation
}
type Query {
externalData: Data
@http(
url: "https://jsonplaceholder.typicode.com/external-api/data"
headers: [
{
key: "Authorization"
value: "Bearer {{.vars.apiKey}}"
}
]
)
}
In the provided example, setting a variable named apiKey
with a placeholder value of "YOUR_API_KEY_HERE" implies that whenever Tailcall fetches data from the externalData
endpoint, it includes the apiKey
in the Authorization header of the HTTP request.
Local variables, like apiKey
, are instrumental in securing access to external services or providing a unified place for configurations. Ensure that sensitive information stored this way is well protected and not exposed unintentionally, if your GraphQL configuration is publicly accessible.
introspection
This setting controls the server's allowance of introspection queries. Introspection, a core feature of GraphQL, allows clients to directly fetch schema information. This capability proves crucial for tools and client applications in comprehending the available types, fields, and operations. By default, the server enables this setting (true
).
schema @server(introspection: false) {
query: Query
mutation: Mutation
}
Although introspection is beneficial during development and debugging stages, consider disabling it in production environments. Turning off introspection in live deployments can enhance security by preventing potential attackers from discerning the schema and any associated business logic or data structures.
queryValidation
The queryValidation
configuration determines if the server checks incoming GraphQL queries against the defined schema. Each query check ensures it matches the schema, preventing errors from incorrect or malformed queries. In some situations, you might want to disable it, notably to enhance server performance at the cost of these checks. This defaults to false
if not specified.
schema @server(queryValidation: true) {
query: Query
mutation: Mutation
}
The example above sets queryValidation
to true
, enabling the validation phase for incoming queries.
Enable this in the development environment to ensure the queries sent are correct and validated. In the production environment, consider disabling it for improved performance.
responseValidation
Tailcall can automatically infer the schema of the HTTP endpoints for you. This information can check responses received from the upstream services. Enabling this setting allows you to do that. If not specified, the default setting for responseValidation
is false
.
schema @server(responseValidation: true) {
query: Query
mutation: Mutation
}
Disabling this setting will offer major performance improvements, but at the potential expense of data integrity.
globalResponseTimeout
The globalResponseTimeout
configuration sets the max duration a query can run before the server terminates it. Essentially, it acts as a safeguard against long-running queries that could strain resources or pose security concerns.
If not explicitly defined, there might be a system-specific or default value that applies.
schema @server(globalResponseTimeout: 5000) {
query: Query
mutation: Mutation
}
In this given example, setting the globalResponseTimeout
to 5000
milliseconds, or 5 seconds, means any query execution taking longer than this duration will be automatically terminated by
Setting an appropriate response timeout in production environments is crucial. This optimizes resource use and serves as a security measure against potential denial-of-service attacks, where adversaries might run complex queries to exhaust server resources.
version
The server uses the HTTP version. If not specified, the default value is HTTP1
. The available options are HTTP1
and HTTP2
.
schema @server(version: HTTP2) {
query: Query
mutation: Mutation
}
cert
The path to certificate(s) for running the server over HTTP2 (HTTPS). If not specified, the default value is null
.
schema @server(cert: "./cert.pem") {
query: Query
mutation: Mutation
}
The certificate can be of any extension, but it's highly recommended to use standards (pem
, crt
, key
).
key
The path to the key for running the server over HTTP2 (HTTPS). If not specified, the default value is null
.
schema @server(key: "./key.pem") {
query: Query
mutation: Mutation
}
The key can be of any extension, but it's highly recommended to use standards (pem
, crt
, key
).
showcase
The @server
directive's showcase
option allows for hands-on experimentation with server configurations in a controlled environment. This feature simplifies the process of exploring and testing different settings.
schema @server(showcase: true) {
query: Query
}
batchRequests
Batching in GraphQL combines requests into one, reducing server round trips.
schema @server(
port: 8000
batchRequests: true
)
Batching can improve performance but may introduce latency if one request in the batch takes longer. It also makes network traffic debugging harder.
routes
This optional field allows you to customize the server's endpoint paths, enabling you to override the default values for the GraphQL and status endpoints. If not specified, the following default paths will be used:
- graphQL:
/graphql
- status:
/status
schema @server(routes: {graphQL: "/tailcall-gql", status: "/health"})
In this example, the GraphQL endpoint is changed to /tailcall-gql
and the status endpoint to /health
.
enableFederation
A boolean flag, if set to true
the Tailcall server will additionally act as federation subgraph. By default, it's disabled.
schema @server(enableFederation: true)