package component:grafbase;
world hooks {
// Error thrown when accessing the headers. Headers names or values
// must not contain any special characters.
enum header-error {
// the given header value is not valid
invalid-header-value,
// the given header name is not valid
invalid-header-name,
}
// Error variant sent if failing to write to access log.
variant log-error {
// The log channel is over capacity. The data is returned to the caller.
channel-full(list<u8>),
// The channel is closed.
channel-closed,
}
// A context object is available in all hooks during the whole request
// lifecycle. It can be used to store custom data in one hook and make it
// available in the hooks executed later in the request.
//
// This resource provides mutable access to the context and is available only
// in the gateway request hook.
resource context {
// Fetches a context value with the given name, if existing.
get: func(name: string) -> option<string>;
// Stores a context value with the given name.
set: func(name: string, value: string);
// Deletes a context value with the given name. Returns the value
// if existing.
delete: func(name: string) -> option<string>;
}
// The context as a read-only object.
resource shared-context {
// Fetches a context value with the given name, if existing.
get: func(name: string) -> option<string>;
// Gets the current trace-id.
trace-id: func() -> string;
}
// Provides access to the request headers. Available in a mutable form
// only in the gateway request hook.
resource headers {
// Gets a header value with the given name.
get: func(name: string) -> option<string>;
// Sets the header value with the given name. Returns an error if the given name
// is not a valid header name.
set: func(name: string, value: string) -> result<_, header-error>;
// Deletes a header value with the given name.
delete: func(name: string) -> option<string>;
// Return all headers as a list of tuples.
entries: func() -> list<tuple<string, string>>;
}
// Defines an edge in a type
record edge-definition {
// The name of the type the edge is part of
parent-type-name: string,
// The name of the field of this edge
field-name: string,
}
// Defines a node
record node-definition {
// The name of the type of this node
type-name: string,
}
// Info about an executed HTTP request.
record executed-http-request {
// The request method.
method: string,
// The request URL.
url: string,
// The response status code.
status-code: u16,
// The outputs of executed on-operation-response hooks for every operation of the request.
on-operation-response-outputs: list<list<u8>>,
}
// An error returned from a field.
record field-error {
// The number of errors.
count: u64,
// The returned data is null.
data-is-null: bool,
}
// An error from a GraphQL request.
record request-error {
// The number of errors.
count: u64,
}
// A status of a GraphQL operation.
variant graphql-response-status {
// Request was successful.
success,
// A field returned an error.
field-error(field-error),
// A request error.
request-error(request-error),
// The request was refused.
refused-request,
}
// Info about an executed operation.
record executed-operation {
// The name of the operation, if present.
name: option<string>,
// The operation document in sanitized form.
document: string,
// The time taken in preparing.
prepare-duration-ms: u64,
// True, if the plan was taken from cache.
cached-plan: bool,
// Time in milliseconds spent executing the operation.
duration-ms: u64,
// The status of the operation.
status: graphql-response-status,
// If queried any subgraphs, the outputs of on-subgraph-response hooks.
// Will be empty if no subgraphs were called.
on-subgraph-response-outputs: list<list<u8>>,
}
// Information on a response
record subgraph-response {
// The milliseconds it took to connect to the host.
connection-time-ms: u64,
// The milliseconds it took for the host to respond with data.
response-time-ms: u64,
// The response status code
status-code: u16
}
// Cache status of a subgraph call.
enum cache-status {
// All data fetched from cache.
hit,
// Some data fetched from cache.
partial-hit,
// Cache miss
miss,
}
// Subgraph response variant.
variant subgraph-request-execution-kind {
// Internal server error in the gateway.
internal-server-error,
// Response prevented by subgraph request hook.
hook-error,
// HTTP request failed.
request-error,
// Request was rate-limited.
rate-limited,
// A response was received.
response(subgraph-response),
}
// Info about an executed subgraph request.
record executed-subgraph-request {
// The name of the subgraph.
subgraph-name: string,
// The request method.
method: string,
// The subgraph URL.
url: string,
// The subgraph responses
executions: list<subgraph-request-execution-kind>,
// The cache status of the subgraph call.
cache-status: cache-status,
// The time in milliseconds taken for the whole operation.
total-duration-ms: u64,
// True, if the subgraph returned any errors.
has-errors: bool,
}
// An HTTP error response.
record error-response {
// HTTP status code. Must be a valid status code. If not, the status code will be 500.
status-code: u16,
// List of GraphQL errors.
errors: list<error>,
}
// An error response can be used to inject an error to the GraphQL response.
record error {
// Adds the given extensions to the response extensions. The first item in
// the tuple is the extension key, and the second item is the extension value.
// The extension value can be string-encoded JSON, which will be converted as
// JSON in the response. It can also be just a string, which will be converted as
// a JSON string in the response.
extensions: list<tuple<string, list<u8>>>,
// The error message.
message: string,
}
// A HTTP client.
resource http-client {
// Executes a request and returns the response, yielding the current future until finished.
execute: static func(request: http-request) -> result<http-response, http-error>;
// Executes multiple requests in parallel, yielding the current future until all requests are done.
execute-many: static func(requests: list<http-request>) -> list<result<http-response, http-error>>;
}
// A sender for the system access log.
resource access-log {
// Sends the data to the access log.
send: static func(data: list<u8>) -> result<_, log-error>;
}
// A HTTP request.
record http-request {
// The HTTP method.
method: http-method,
// The URL to send the request to.
url: string,
// The headers to send with the request. Keys and values must be ASCII strings.
headers: list<tuple<string, string>>,
// The body of the request. If the body is set, the Content-Type header must be set.
body: list<u8>,
// The timeout in milliseconds for the request. If not set, no timeout is used.
timeout-ms: option<u64>,
}
// The HTTP method.
enum http-method {
// The GET method requests a representation of the specified resource. Requests using GET should only retrieve data.
get,
// The POST method is used to submit an entity to the specified resource, often causing a change in state or side effects on the server.
post,
// The PUT method replaces all current representations of the target resource with the request payload.
put,
// The DELETE method deletes the specified resource.
delete,
// The PATCH method is used to apply partial modifications to a resource.
patch,
// The HEAD method asks for a response identical to that of a GET request, but without the response body.
head,
// The OPTIONS method is used to describe the communication options for the target resource.
options,
// The CONNECT method establishes a tunnel to the server identified by the target resource.
connect,
// The TRACE method performs a message loop-back test along the path to the target resource.
trace,
}
// An HTTP response.
record http-response {
// The HTTP status code.
status: u16,
// The HTTP version.
version: http-version,
// The headers of the response.
headers: list<tuple<string, string>>,
// The body of the response.
body: list<u8>,
}
// The HTTP version.
enum http-version {
// The HTTP/0.9 version.
http09,
// The HTTP/1.0 version.
http10,
// The HTTP/1.1 version.
http11,
// The HTTP/2.0 version.
http20,
// The HTTP/3.0 version.
http30,
}
// An HTTP error.
variant http-error {
// The request timed out.
timeout,
// The request failed due to an error (invalid user data).
request(string),
// The request failed due to an error (server connection failed).
connect(string),
}
// GraphQL HTTP request that will be sent to a subgraph. Allows inspecting and modifying the method, url and headers.
resource subgraph-request {
// The HTTP method.
method: func() -> http-method;
set-method: func(method: http-method);
// The URL to send the request to.
url: func() -> string;
set-url: func(url: string) -> result<_, string>;
// The headers to send with the request.
headers: func() -> headers;
}
// The hook is called in the federated gateway just before authentication. It can be used
// to read and modify the request headers. The context object is provided in a mutable form,
// allowing storage for the subsequent hooks to read.
//
// If returning an error from the hook, the request processing is stopped and the given error
// returned to the client.
export on-gateway-request: func(context: context, url: string, headers: headers) -> result<_, error-response>;
// The hook is called just before requesting a subgraph, after rate limiting is done. It can be used
// to read and modify the subgraph request headers. If returning an error, the subgraph is not requested.
export on-subgraph-request: func(
context: shared-context,
subgraph-name: string,
request: subgraph-request
) -> result<_, error>;
// The hook is called in the request cycle if the schema defines an authorization directive on
// an edge, providing the arguments of the edge selected in the directive, the definition of the esge
// and the metadata of the directive to the hook.
//
// The hook is run before fetching any data.
//
// The result, if an error, will stop the request execution and return an error back to the user.
// Result of the edge will be null for an error response.
export authorize-edge-pre-execution: func(
context: shared-context,
definition: edge-definition,
arguments: string,
metadata: string
) -> result<_, error>;
// The hook is called in the request cycle if the schema defines an authorization directive to
// a node, providing the definition of the node and the metadata of the directive to the hook.
//
// The hook is run before fetching any data.
//
// The result, if an error, will stop the request execution and return an error back to the user.
// Result of the edge will be null for an error response.
export authorize-node-pre-execution: func(
context: shared-context,
definition: node-definition,
metadata: string
) -> result<_, error>;
// The hook is called in the request cycle if the schema defines an authorization directive on
// an edge with the fields argument, providing fields from the parent node. The hook gets the
// parent type information, and a list of data with the defined fields of the parent for every
// child loaded by the parent query.
//
// The hook is run after fetching the data.
//
// The result can be one of the following:
//
// - A list of one item, which dictates the result for every child loaded from the edge
// - A list of many items, each one defining if the child should be shown or not
//
// Providing any other response will lead to the whole authorization hook failing and data not
// returned to the user.
//
// The list item can either be an empty Ok, which returns the edge data to the client. Or the
// item can be an error and the edge access is denied. The error data will be propagated to the
// response errors.
export authorize-parent-edge-post-execution: func(
context: shared-context,
definition: edge-definition,
parents: list<string>,
metadata: string
) -> list<result<_, error>>;
// The hook is called in the request cycle if the schema defines an authorization directive on
// an edge with the node argument, providing fields from the child node. The hook gets the parent type information,
// and a list of data with the defined fields for every child loaded by the parent query.
//
// The hook is run after fetching the data.
//
// The result can be one of the following:
//
// - A list of one item, which dictates the result for every child loaded from the edge
// - A list of many items, each one defining if the child should be shown or not
//
// Providing any other response will lead to the whole authorization hook failing and data not
// returned to the user.
//
// The list item can either be an empty Ok, which returns the edge data to the client. Or the
// item can be an error and the edge access is denied. The error data will be propagated to the
// response errors.
export authorize-edge-node-post-execution: func(
context: shared-context,
definition: edge-definition,
nodes: list<string>,
metadata: string
) -> list<result<_, error>>;
// The hook is called in the request cycle if the schema defines an authorization directive on
// an edge with the node and fields arguments, providing fields from the child node. The hook gets
// the parent type information, and a list of data with tuples of the parent data and a list of child data.
//
// The first part of the tuple is defined by the directive's fields argument and the second part by
// the node argument.
//
// The hook is run after fetching the data.
//
// The result can be one of the following:
//
// - A list of one item, which dictates the result for every child loaded from the edge
// - A list of many items, each one defining if the child should be shown or not
//
// Providing any other response will lead to the whole authorization hook failing and data not
// returned to the user.
//
// The list item can either be an empty Ok, which returns the edge data to the client. Or the
// item can be an error and the edge access is denied. The error data will be propagated to the
// response errors.
export authorize-edge-post-execution: func(
context: shared-context,
definition: edge-definition,
edges: list<tuple<string, list<string>>>,
metadata: string
) -> list<result<_, error>>;
// The hook is called after a subgraph entity has been either requested or fetched from cache.
// The output is a list of bytes, which will be available in the on-operation-response hook.
export on-subgraph-response: func(
context: shared-context,
request: executed-subgraph-request,
) -> list<u8>;
// The hook is called after a request is handled in the gateway. The output is a list of bytes,
// which will be available in the on-http-response hook.
export on-operation-response: func(
context: shared-context,
request: executed-operation,
) -> list<u8>;
// The hook is called right before a response is sent to the user.
export on-http-response: func(
context: shared-context,
request: executed-http-request,
);
// The hooks initialization function. Must be called before any other hook function.
export init-hooks: func() -> s64;
}