schema

package
v0.9.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 8, 2023 License: Apache-2.0 Imports: 54 Imported by: 1

README

Core API proposal

This directory contains a proposal for a complete GraphQL API for Dagger. It is written with the following goals in mind:

  1. Feature parity with Dagger 0.2
  2. Close to feature parity with Buildkit, with an incremental path to reaching full parity in the future
  3. Follow established graphql best practices
  4. Sove as many outstanding DX problems as possible

Reference

DX problems solved

Some problems in the DX that are not yet resolved, and this proposal would help solve, include:

  • Uncertainty as to how to express uploads in a graphql-friendly way (deployment, image push, git push, etc)
  • Chaining of FS operations greatly reduces verbosity, but cannot be applied all the time
  • Transitioning a script to an extension requires non-trivial refactoring, to tease apart the script-specific code from the underlying "API".
  • The API sandbox is amazing for prototyping small queries, but of limited use when multiple queries must reference each other. This is because the native code doing the stitching cannot be run by the playground, so filesystem IDs must be manually copy-pasted between queries.

Design highlights

withX and withoutX

To avoid the use of rpc-style verbs (a graphql best practice) and maximize chaining (a strength of our DX), we use the terminology withX and withoutX.

A field of the form withX returns the same object with content X added or changed.

Example:

"An empty directory with a README copied to it"
query readmeDir($readme: FileID!) {
  directory {
    withFile(source: $readme, path: "README.md") {
      id
    }
}

"An empty container with an app directory mounted into it"
query appContainer($app: DirectoryID!) {
  container {
    withMountedDirectory(source: $app, path: "/app") {
      id
    }
  }
}

A field of the form withoutX returns the same object with content X removed.

"Remove node_modules from a JS project"
query removeNodeModules($dir: DirectoryID!) {
  directory(id: $dir) {
    withoutDirectory(path: "node_modules") {
      id
    }
  }
}
Secrets

Secret handling has been simplified and made more consistent with Directory handling.

  • Secrets have an ID, and can be loaded by ID in the standard graphql manner
  • Secrets can be created in one of two ways:
    1. From an environment variable: type Environment { secret }
    2. From a file: type Directory { secret }
Embrace the llb / Dockerfile model

The Container type proposes an expansive definition of the container, similar to the Buildkit/Dockerfile model. A Container is:

  1. A filesystem state
  2. An OCI artifact which can be pulled from, and pushed to a repository at any time
  3. A persistent configuration to be applied to all commands executed inside it

This is similar to how buildkit models llb state, and how the Dockerfile language models stage state. Note that Dagger extends this model to include even mount configuration (which are scoped to exec in buildkit, but scoped to container in dagger).

Examples:

"""
Download a file over HTTP in a very convoluted way:

1. Download a base linux container
2. Install curl
3. Download the file into the container
4. Load and return the file
"""
query convolutedDownload($url: String!) {
  container {
    from(address: "index.docker.io/alpine:latest") {
      exec(args: ["apk", "add", "curl"]) {
        exec(args: ["curl", "-o", "/tmp/download", $url) {
          file(path: "/tmp/download") {
            id
         }
      }
    }
  }
}

"""
Specialize two containers from a common base
"""
query twoContainers {
  container {
    from(address: "alpine") {
      debug: withVariable(name: "DEBUG", value: "1") {
        id
        exec(args: ["env"]) {
          stdout
        }
      }
      noDebug: withVariable(name: "DEBUG", value: "0") {
        id
        exec(args: ["env"]) {
          stdout
        }
      }
    }
  }
}

Documentation

Index

Constants

View Source
const (
	ContentTypeJSON           = "application/json"
	ContentTypeGraphQL        = "application/graphql"
	ContentTypeFormURLEncoded = "application/x-www-form-urlencoded"
)

Variables

View Source
var (
	ErrMergeTypeConflict   = errors.New("object type re-defined")
	ErrMergeFieldConflict  = errors.New("field re-defined")
	ErrMergeScalarConflict = errors.New("scalar re-defined")
)
View Source
var Cache string
View Source
var Container string
View Source
var Directory string
View Source
var File string
View Source
var HTTP string
View Source
var Host string
View Source
var InternalSDK string
View Source
var Module string
View Source
var Platform string
View Source
var Query string
View Source
var Secret string
View Source
var Service string
View Source
var Socket string
View Source
var TypeDef string

Functions

func ErrResolver added in v0.8.0

func ErrResolver(err error) graphql.FieldResolveFn

func PassthroughResolver added in v0.8.0

func PassthroughResolver(p graphql.ResolveParams) (any, error)

func ResolveIDable added in v0.9.0

func ResolveIDable[T any](rs Resolvers, name string, obj ObjectResolver)

func ToResolver added in v0.8.0

func ToResolver[P any, A any, R any](f func(context.Context, P, A) (R, error)) graphql.FieldResolveFn

ToResolver transforms any function f with a context.Context, a parent P and some args A that returns a Response R and an error into a graphql resolver graphql.FieldResolveFn.

func ToVoidResolver added in v0.8.8

func ToVoidResolver[P any, A any](f func(context.Context, P, A) error) graphql.FieldResolveFn

Types

type APIServer added in v0.9.4

type APIServer struct {
	// contains filtered or unexported fields
}

func New

func New(ctx context.Context, params InitializeArgs) (*APIServer, error)

func (*APIServer) AddModFromMetadata added in v0.9.4

func (s *APIServer) AddModFromMetadata(
	ctx context.Context,
	modMeta *core.Module,
	pipeline pipeline.Path,
) (*UserMod, error)

func (*APIServer) AddModFromRef added in v0.9.4

func (s *APIServer) AddModFromRef(
	ctx context.Context,
	ref string,
	parentMod *core.Module,
	pipeline pipeline.Path,
) (*UserMod, error)

func (*APIServer) CurrentFunctionCall added in v0.9.4

func (s *APIServer) CurrentFunctionCall(ctx context.Context) (*core.FunctionCall, error)

func (*APIServer) CurrentModule added in v0.9.4

func (s *APIServer) CurrentModule(ctx context.Context) (*UserMod, error)

func (*APIServer) GetModFromMetadata added in v0.9.4

func (s *APIServer) GetModFromMetadata(ctx context.Context, modMeta *core.Module) (*UserMod, error)

func (*APIServer) MuxEndpoint added in v0.9.4

func (s *APIServer) MuxEndpoint(ctx context.Context, path string, handler http.Handler) error

func (*APIServer) RegisterFunctionCall added in v0.9.4

func (s *APIServer) RegisterFunctionCall(dgst digest.Digest, deps *ModDeps, mod *UserMod, call *core.FunctionCall) error

func (*APIServer) ServeHTTP added in v0.9.4

func (s *APIServer) ServeHTTP(w http.ResponseWriter, r *http.Request)

func (*APIServer) ServeModuleToMainClient added in v0.9.4

func (s *APIServer) ServeModuleToMainClient(ctx context.Context, modMeta *core.Module) error

func (*APIServer) ShutdownClient added in v0.9.4

func (s *APIServer) ShutdownClient(ctx context.Context, client *engine.ClientMetadata) error

type CallOpts added in v0.9.4

type CallOpts struct {
	Inputs         []*core.CallInput
	ParentVal      any
	Cache          bool
	Pipeline       pipeline.Path
	SkipSelfSchema bool
}

type CompiledSchema added in v0.9.4

type CompiledSchema struct {
	SchemaResolvers
	Compiled *graphql.Schema
}

type CoreMod added in v0.9.4

type CoreMod struct {
	// contains filtered or unexported fields
}

CoreMod is a special implementation of Mod for our core API, which is not *technically* a true module yet but can be treated as one in terms of dependencies. It has no dependencies itself and is currently an implicit dependency of every user module.

func (*CoreMod) DagDigest added in v0.9.4

func (m *CoreMod) DagDigest() digest.Digest

func (*CoreMod) Dependencies added in v0.9.4

func (m *CoreMod) Dependencies() []Mod

func (*CoreMod) ModTypeFor added in v0.9.4

func (m *CoreMod) ModTypeFor(ctx context.Context, typeDef *core.TypeDef, checkDirectDeps bool) (ModType, bool, error)

func (*CoreMod) Name added in v0.9.4

func (m *CoreMod) Name() string

func (*CoreMod) Schema added in v0.9.4

func (m *CoreMod) Schema(_ context.Context) ([]SchemaResolvers, error)

func (*CoreMod) SchemaIntrospectionJSON added in v0.9.4

func (m *CoreMod) SchemaIntrospectionJSON(_ context.Context) (string, error)

type CoreModObject added in v0.9.4

type CoreModObject struct {
	// contains filtered or unexported fields
}

CoreModObject represents objects from core (Container, Directory, etc.)

func (*CoreModObject) ConvertFromSDKResult added in v0.9.4

func (obj *CoreModObject) ConvertFromSDKResult(_ context.Context, value any) (any, error)

func (*CoreModObject) ConvertToSDKInput added in v0.9.4

func (obj *CoreModObject) ConvertToSDKInput(ctx context.Context, value any) (any, error)

func (*CoreModObject) SourceMod added in v0.9.4

func (obj *CoreModObject) SourceMod() Mod

type EnvVariable

type EnvVariable struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type ExposedPort added in v0.3.13

type ExposedPort struct {
	Port        int     `json:"port"`
	Protocol    string  `json:"protocol"`
	Description *string `json:"description,omitempty"`
}

NB(vito): we have to use a different type with a regular string Protocol field so that the enum mapping works.

type FieldResolvers added in v0.8.0

type FieldResolvers interface {
	Resolver
	Fields() map[string]graphql.FieldResolveFn
	SetField(string, graphql.FieldResolveFn)
	Clone() FieldResolvers
}

type Handler added in v0.8.8

type Handler struct {
	Schema *graphql.Schema
	// contains filtered or unexported fields
}

func NewHandler added in v0.8.8

func NewHandler(p *HandlerConfig) *Handler

func (*Handler) ContextHandler added in v0.8.8

func (h *Handler) ContextHandler(ctx context.Context, w http.ResponseWriter, r *http.Request)

ContextHandler provides an entrypoint into executing graphQL queries with a user-provided context.

func (*Handler) ServeHTTP added in v0.8.8

func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP provides an entrypoint into executing graphQL queries.

type HandlerConfig added in v0.8.8

type HandlerConfig struct {
	Schema           *graphql.Schema
	Pretty           bool
	RootObjectFn     RootObjectFn
	ResultCallbackFn ResultCallbackFn
	FormatErrorFn    func(err error) gqlerrors.FormattedError
}

func NewConfig added in v0.8.8

func NewConfig() *HandlerConfig

type IDableObjectResolver added in v0.8.0

type IDableObjectResolver interface {
	FromID(id string) (any, error)
	ToID(any) (string, error)
	Resolver
}

func ToIDableObjectResolver added in v0.8.0

func ToIDableObjectResolver[T any, I ~string](
	idToObject func(I) (*T, error),
	objectToID func(*T) (I, error),
	r ObjectResolver,
) IDableObjectResolver

type InitializeArgs

type InitializeArgs struct {
	BuildkitClient *buildkit.Client
	Platform       specs.Platform
	ProgSockPath   string
	OCIStore       content.Store
	LeaseManager   *leaseutil.Manager
	Auth           *auth.RegistryAuthProvider
	Secrets        *core.SecretStore
}

type InvalidInputError added in v0.8.0

type InvalidInputError struct {
	Err error
}

func (InvalidInputError) Error added in v0.8.0

func (e InvalidInputError) Error() string

func (InvalidInputError) Unwrap added in v0.8.0

func (e InvalidInputError) Unwrap() error

type Label added in v0.3.10

type Label struct {
	Name  string `json:"name"`
	Value string `json:"value"`
}

type ListType added in v0.9.4

type ListType struct {
	// contains filtered or unexported fields
}

func (*ListType) ConvertFromSDKResult added in v0.9.4

func (t *ListType) ConvertFromSDKResult(ctx context.Context, value any) (any, error)

func (*ListType) ConvertToSDKInput added in v0.9.4

func (t *ListType) ConvertToSDKInput(ctx context.Context, value any) (any, error)

func (*ListType) SourceMod added in v0.9.4

func (t *ListType) SourceMod() Mod

type Mod added in v0.9.4

type Mod interface {
	// The name of the module
	Name() string

	// The digest of the module itself plus the recursive digests of the DAG it depends on
	DagDigest() digest.Digest

	// The direct dependencies of this module
	Dependencies() []Mod

	// The schema+resolvers exposed by this module (does not include dependencies)
	Schema(context.Context) ([]SchemaResolvers, error)

	// The introspection json for this module's schema
	SchemaIntrospectionJSON(context.Context) (string, error)

	// ModTypeFor returns the ModType for the given typedef based on this module's schema.
	// The returned type will have any namespacing already applied.
	// If checkDirectDeps is true, then its direct dependencies will also be checked.
	ModTypeFor(ctx context.Context, typeDef *core.TypeDef, checkDirectDeps bool) (ModType, bool, error)
}

Mod is a module in loaded into the server's DAG of modules; it's the vertex type of the DAG. It's an interface so we can abstract over user modules and core and treat them the same.

type ModDeps added in v0.9.4

type ModDeps struct {
	// contains filtered or unexported fields
}

ModDeps represents a set of dependencies for a module or for a caller depending on a particular set of modules to be served.

func (*ModDeps) DagDigest added in v0.9.4

func (d *ModDeps) DagDigest() digest.Digest

The digest of all the modules in the DAG

func (*ModDeps) ModTypeFor added in v0.9.4

func (d *ModDeps) ModTypeFor(ctx context.Context, typeDef *core.TypeDef) (ModType, bool, error)

Search the deps for the given type def, returning the ModType if found. This does not recurse to transitive dependencies; it only returns types directly exposed by the schema of the top-level deps.

func (*ModDeps) Schema added in v0.9.4

func (d *ModDeps) Schema(ctx context.Context) (*CompiledSchema, error)

The combined schema exposed by each mod in this set of dependencies

func (*ModDeps) SchemaIntrospectionJSON added in v0.9.4

func (d *ModDeps) SchemaIntrospectionJSON(ctx context.Context) (string, error)

The introspection json for combined schema exposed by each mod in this set of dependencies

type ModType added in v0.9.4

type ModType interface {
	// ConvertFromSDKResult converts a value returned from an SDK into values expected by the server,
	// including conversion of IDs to their "unpacked" objects
	ConvertFromSDKResult(ctx context.Context, value any) (any, error)
	// ConvertToSDKInput converts a value from the server into a value expected by the SDK, which may
	// include converting objects to their IDs
	ConvertToSDKInput(ctx context.Context, value any) (any, error)
	// SourceMod is the module in which this type was originally defined
	SourceMod() Mod
}

ModType wraps the core TypeDef type with schema specific concerns like ID conversion and tracking of the module in which the type was originally defined.

type ObjectResolver added in v0.8.0

type ObjectResolver map[string]graphql.FieldResolveFn

func (ObjectResolver) Clone added in v0.9.4

func (r ObjectResolver) Clone() FieldResolvers

func (ObjectResolver) Fields added in v0.8.0

func (ObjectResolver) SetField added in v0.8.0

func (r ObjectResolver) SetField(name string, fn graphql.FieldResolveFn)

type PrimitiveType added in v0.9.4

type PrimitiveType struct{}

PrimitiveType are the basic types like string, int, bool, void, etc.

func (*PrimitiveType) ConvertFromSDKResult added in v0.9.4

func (t *PrimitiveType) ConvertFromSDKResult(ctx context.Context, value any) (any, error)

func (*PrimitiveType) ConvertToSDKInput added in v0.9.4

func (t *PrimitiveType) ConvertToSDKInput(ctx context.Context, value any) (any, error)

func (*PrimitiveType) SourceMod added in v0.9.4

func (t *PrimitiveType) SourceMod() Mod

type RequestOptions added in v0.8.8

type RequestOptions struct {
	Query         string                 `json:"query" url:"query" schema:"query"`
	Variables     map[string]interface{} `json:"variables" url:"variables" schema:"variables"`
	OperationName string                 `json:"operationName" url:"operationName" schema:"operationName"`
}

func NewRequestOptions added in v0.8.8

func NewRequestOptions(r *http.Request) *RequestOptions

RequestOptions Parses a http.Request into GraphQL request options struct

type Resolver added in v0.8.0

type Resolver interface {
	// contains filtered or unexported methods
}

type Resolvers added in v0.8.0

type Resolvers map[string]Resolver

type ResultCallbackFn added in v0.8.8

type ResultCallbackFn func(ctx context.Context, params *graphql.Params, result *graphql.Result, responseBody []byte)

type RootObjectFn added in v0.8.8

type RootObjectFn func(ctx context.Context, r *http.Request) map[string]interface{}

RootObjectFn allows a user to generate a RootObject per request

type SDK added in v0.9.0

type SDK interface {
	/* Codegen generates code for the module at the given source directory and subpath.

	The Code field of the returned GeneratedCode object should be the generated contents of the module sourceDirSubpath,
	in the case where that's different than the root of the sourceDir.

	The provided Module is not fully initialized; the Runtime field will not be set yet.
	*/
	Codegen(ctx context.Context, mod *UserMod) (*core.GeneratedCode, error)

	/* Runtime returns a container that is used to execute module code at runtime in the Dagger engine.

	The provided Module is not fully initialized; the Runtime field will not be set yet.
	*/
	Runtime(ctx context.Context, mod *UserMod) (*core.Container, error)
}

An SDK is an implementation of the functionality needed to generate code for and execute a module.

There is one special SDK, the Go SDK, which is implemented in `goSDK` below. It's used as the "seed" for all other SDK implementations.

All other SDKs are themselves implemented as Modules, with Functions matching the two defined in this SDK interface.

An SDK Module needs to choose its own SDK for its implementation. This can be "well-known" built-in SDKs like "go", "python", etc. Or it can be any external module as specified with a module ref.

You can thus think of SDK Modules as a DAG of dependencies, with each SDK using a different SDK to implement its Module, with the Go SDK as the root of the DAG and the only one without any dependencies.

Built-in SDKs are also a bit special in that they come bundled w/ the engine container image, which allows them to be used without hard dependencies on the internet. They are loaded w/ the `loadBuiltinSDK` function below, which loads them as modules from the engine container.

type ScalarResolver added in v0.8.0

type ScalarResolver struct {
	Serialize    graphql.SerializeFn
	ParseValue   graphql.ParseValueFn
	ParseLiteral graphql.ParseLiteralFn
}

type SchemaResolvers added in v0.9.4

type SchemaResolvers interface {
	Schema() string
	Resolvers() Resolvers
}

func StaticSchema added in v0.8.0

func StaticSchema(p StaticSchemaParams) SchemaResolvers

type SecretPlaintext added in v0.6.0

type SecretPlaintext string

func (SecretPlaintext) MarshalText added in v0.6.0

func (s SecretPlaintext) MarshalText() ([]byte, error)

This method ensures that the progrock vertex info does not display the plaintext.

type StaticSchemaParams added in v0.8.0

type StaticSchemaParams struct {
	Name      string
	Schema    string
	Resolvers Resolvers
}

type UserMod added in v0.9.4

type UserMod struct {
	// contains filtered or unexported fields
}

A user defined module loaded into this server's DAG.

func (*UserMod) Codegen added in v0.9.4

func (m *UserMod) Codegen(ctx context.Context) (*core.GeneratedCode, error)

func (*UserMod) DagDigest added in v0.9.4

func (m *UserMod) DagDigest() digest.Digest

func (*UserMod) Dependencies added in v0.9.4

func (m *UserMod) Dependencies() []Mod

func (*UserMod) MainModuleObject added in v0.9.4

func (m *UserMod) MainModuleObject(ctx context.Context) (*UserModObject, error)

func (*UserMod) ModTypeFor added in v0.9.4

func (m *UserMod) ModTypeFor(ctx context.Context, typeDef *core.TypeDef, checkDirectDeps bool) (ModType, bool, error)

func (*UserMod) Name added in v0.9.4

func (m *UserMod) Name() string

func (*UserMod) Objects added in v0.9.4

func (m *UserMod) Objects(ctx context.Context) (loadedObjects []*UserModObject, rerr error)

The objects defined by this module, with namespacing applied

func (*UserMod) Runtime added in v0.9.4

func (m *UserMod) Runtime(ctx context.Context) (*core.Container, error)

func (*UserMod) Schema added in v0.9.4

func (m *UserMod) Schema(ctx context.Context) ([]SchemaResolvers, error)

func (*UserMod) SchemaIntrospectionJSON added in v0.9.4

func (m *UserMod) SchemaIntrospectionJSON(ctx context.Context) (string, error)

type UserModField added in v0.9.4

type UserModField struct {
	// contains filtered or unexported fields
}

func (*UserModField) Schema added in v0.9.4

type UserModFunction added in v0.9.4

type UserModFunction struct {
	// contains filtered or unexported fields
}

func (*UserModFunction) Call added in v0.9.4

func (fn *UserModFunction) Call(ctx context.Context, opts *CallOpts) (any, error)

func (*UserModFunction) Digest added in v0.9.4

func (fn *UserModFunction) Digest() digest.Digest

func (*UserModFunction) Schema added in v0.9.4

type UserModFunctionArg added in v0.9.4

type UserModFunctionArg struct {
	// contains filtered or unexported fields
}

type UserModObject added in v0.9.4

type UserModObject struct {
	// contains filtered or unexported fields
}

UserModObject is an object defined by a user module

func (*UserModObject) ConvertFromSDKResult added in v0.9.4

func (obj *UserModObject) ConvertFromSDKResult(ctx context.Context, value any) (any, error)

func (*UserModObject) ConvertToSDKInput added in v0.9.4

func (obj *UserModObject) ConvertToSDKInput(ctx context.Context, value any) (any, error)

func (*UserModObject) FieldByName added in v0.9.4

func (obj *UserModObject) FieldByName(ctx context.Context, name string) (*UserModField, bool, error)

func (*UserModObject) Fields added in v0.9.4

func (obj *UserModObject) Fields(ctx context.Context) ([]*UserModField, error)

func (*UserModObject) FunctionByName added in v0.9.4

func (obj *UserModObject) FunctionByName(ctx context.Context, name string) (*UserModFunction, bool, error)

func (*UserModObject) Functions added in v0.9.4

func (obj *UserModObject) Functions(ctx context.Context) ([]*UserModFunction, error)

func (*UserModObject) Schema added in v0.9.4

func (*UserModObject) SourceMod added in v0.9.4

func (obj *UserModObject) SourceMod() Mod

func (*UserModObject) TypeDef added in v0.9.4

func (obj *UserModObject) TypeDef() *core.TypeDef

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL