Dagger Node.js SDK 0.3: API improvements, better error handling and less boilerplate

December 12, 2022

Dec 12, 2022

Share
Share
Share
Share

It's been three weeks since we released the Dagger Node.js SDK 0.1.0. Since then, we've received many questions and suggestions from the community and we've incorporated several of them in our latest release, the Dagger Node.js SDK 0.3.0.

This version introduces two breaking API changes. However, we believe the improved API allows you to write much shorter code, which is significantly better in the long run.

Get Started

Dagger Node.js SDK 0.3.0 Highlights

Optional parameters as objects

You can now use objects for optional parameters.

  • Required parameters can be provided directly to functions as positional arguments.

  • Optional parameters can be provided through an object that lets you mix and match the options you want.

Before:

const source = await 
client.container().from(“alpine:16).withExec([“echo”, “foo”], 
undefined, undefined, undefined, true)

After:

const source = await 
client.container().from('alpine').withExec(['echo', 'foo'], 
{experimentalPrivilegedNesting: true})

Read the SDK documentation

Less boilerplate

You no longer need to pass IDs, which makes the code you need to write much shorter.

Before:

const source = await client.host().directory(".").id()
const c = await client
    .container()
    .from("node:16")
    .withMountedDirectory("/src", source.id)

After:

const source = client.host().directory(.)
const c = await client
    .container()
    .from("node:16")
    .withMountedDirectory("/src", source)

Read the SDK documentation

Centralized error handling

Debugging and error handling is faster and easier with new, more precise error messages and codes.

Before:

file:///home/user/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:255
        	throw new Error("failed to read port from engine session");
              	^
Error: failed to read port from engine session
	at DockerImage.<anonymous> (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:255:19)
	at Generator.next (<anonymous>

After:

Error: buildkit failed to respond
file:///home/user/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:262
        	throw new EngineSessionPortParseError("No line was found to parse the engine port");
              	^
EngineSessionPortParseError [EngineSessionPortError]: No line was found to parse the engine port
	at DockerImage.<anonymous> (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:262:19)
	at Generator.next (<anonymous>)
	at fulfilled (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:4:58)
	at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  cause

Learn more about the new error types

Improved filesystem API

We've added new methods to make it easier to work with the container filesystem

  • Container.WithDirectory: returns the container plus a directory written at the given path.

  • Container.WithFile: returns the container plus the contents of the given file copied to the given path.

  • Container.WithNewFile: returns the container plus a new file written at the given path.

WithNewFile

Before:

let textFile = fs.openSync("myTextFile", "w")
fs.writeFileSync(textFile, "my text content")

let packageFile = await client
    .host()
    .workdir(undefined, ["myTextFile"])
    .id()

await client
    .container()
    .from("node")
    .withMountedDirectory("/tmp/filedir", packageFile.id)
    .exec([ "cat", "/tmp/filedir/myTextFile" ])
    .stdout()
    .contents()

After:

await client
    .container()
    .from("node")
    .withNewFile("/tmp/filedir/myTextFile", { contents: "my text content" })
    .withExec([ "cat", "/tmp/filedir/myTextFile" ])
    .stdout()

Read the SDK documentation

We believe these changes bring the overall experience of using the SDK closer to what Node.js developers expect and use elsewhere, and also result in shorter and more readable code.

Thank you to the Dagger Community for your continuous and quick feedback. We look forward to releasing more features and documentation soon! In the meanwhile, if you have feedback or would like to suggest new features or documentation, let us know on Discord or create a GitHub issue.


It's been three weeks since we released the Dagger Node.js SDK 0.1.0. Since then, we've received many questions and suggestions from the community and we've incorporated several of them in our latest release, the Dagger Node.js SDK 0.3.0.

This version introduces two breaking API changes. However, we believe the improved API allows you to write much shorter code, which is significantly better in the long run.

Get Started

Dagger Node.js SDK 0.3.0 Highlights

Optional parameters as objects

You can now use objects for optional parameters.

  • Required parameters can be provided directly to functions as positional arguments.

  • Optional parameters can be provided through an object that lets you mix and match the options you want.

Before:

const source = await 
client.container().from(“alpine:16).withExec([“echo”, “foo”], 
undefined, undefined, undefined, true)

After:

const source = await 
client.container().from('alpine').withExec(['echo', 'foo'], 
{experimentalPrivilegedNesting: true})

Read the SDK documentation

Less boilerplate

You no longer need to pass IDs, which makes the code you need to write much shorter.

Before:

const source = await client.host().directory(".").id()
const c = await client
    .container()
    .from("node:16")
    .withMountedDirectory("/src", source.id)

After:

const source = client.host().directory(.)
const c = await client
    .container()
    .from("node:16")
    .withMountedDirectory("/src", source)

Read the SDK documentation

Centralized error handling

Debugging and error handling is faster and easier with new, more precise error messages and codes.

Before:

file:///home/user/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:255
        	throw new Error("failed to read port from engine session");
              	^
Error: failed to read port from engine session
	at DockerImage.<anonymous> (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:255:19)
	at Generator.next (<anonymous>

After:

Error: buildkit failed to respond
file:///home/user/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:262
        	throw new EngineSessionPortParseError("No line was found to parse the engine port");
              	^
EngineSessionPortParseError [EngineSessionPortError]: No line was found to parse the engine port
	at DockerImage.<anonymous> (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:262:19)
	at Generator.next (<anonymous>)
	at fulfilled (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:4:58)
	at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  cause

Learn more about the new error types

Improved filesystem API

We've added new methods to make it easier to work with the container filesystem

  • Container.WithDirectory: returns the container plus a directory written at the given path.

  • Container.WithFile: returns the container plus the contents of the given file copied to the given path.

  • Container.WithNewFile: returns the container plus a new file written at the given path.

WithNewFile

Before:

let textFile = fs.openSync("myTextFile", "w")
fs.writeFileSync(textFile, "my text content")

let packageFile = await client
    .host()
    .workdir(undefined, ["myTextFile"])
    .id()

await client
    .container()
    .from("node")
    .withMountedDirectory("/tmp/filedir", packageFile.id)
    .exec([ "cat", "/tmp/filedir/myTextFile" ])
    .stdout()
    .contents()

After:

await client
    .container()
    .from("node")
    .withNewFile("/tmp/filedir/myTextFile", { contents: "my text content" })
    .withExec([ "cat", "/tmp/filedir/myTextFile" ])
    .stdout()

Read the SDK documentation

We believe these changes bring the overall experience of using the SDK closer to what Node.js developers expect and use elsewhere, and also result in shorter and more readable code.

Thank you to the Dagger Community for your continuous and quick feedback. We look forward to releasing more features and documentation soon! In the meanwhile, if you have feedback or would like to suggest new features or documentation, let us know on Discord or create a GitHub issue.


It's been three weeks since we released the Dagger Node.js SDK 0.1.0. Since then, we've received many questions and suggestions from the community and we've incorporated several of them in our latest release, the Dagger Node.js SDK 0.3.0.

This version introduces two breaking API changes. However, we believe the improved API allows you to write much shorter code, which is significantly better in the long run.

Get Started

Dagger Node.js SDK 0.3.0 Highlights

Optional parameters as objects

You can now use objects for optional parameters.

  • Required parameters can be provided directly to functions as positional arguments.

  • Optional parameters can be provided through an object that lets you mix and match the options you want.

Before:

const source = await 
client.container().from(“alpine:16).withExec([“echo”, “foo”], 
undefined, undefined, undefined, true)

After:

const source = await 
client.container().from('alpine').withExec(['echo', 'foo'], 
{experimentalPrivilegedNesting: true})

Read the SDK documentation

Less boilerplate

You no longer need to pass IDs, which makes the code you need to write much shorter.

Before:

const source = await client.host().directory(".").id()
const c = await client
    .container()
    .from("node:16")
    .withMountedDirectory("/src", source.id)

After:

const source = client.host().directory(.)
const c = await client
    .container()
    .from("node:16")
    .withMountedDirectory("/src", source)

Read the SDK documentation

Centralized error handling

Debugging and error handling is faster and easier with new, more precise error messages and codes.

Before:

file:///home/user/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:255
        	throw new Error("failed to read port from engine session");
              	^
Error: failed to read port from engine session
	at DockerImage.<anonymous> (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:255:19)
	at Generator.next (<anonymous>

After:

Error: buildkit failed to respond
file:///home/user/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:262
        	throw new EngineSessionPortParseError("No line was found to parse the engine port");
              	^
EngineSessionPortParseError [EngineSessionPortError]: No line was found to parse the engine port
	at DockerImage.<anonymous> (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:262:19)
	at Generator.next (<anonymous>)
	at fulfilled (file:///home/dolanor/src/demos/node_modules/@dagger.io/dagger/dist/provisioning/docker-provision/image.js:4:58)
	at processTicksAndRejections (node:internal/process/task_queues:95:5) {
  cause

Learn more about the new error types

Improved filesystem API

We've added new methods to make it easier to work with the container filesystem

  • Container.WithDirectory: returns the container plus a directory written at the given path.

  • Container.WithFile: returns the container plus the contents of the given file copied to the given path.

  • Container.WithNewFile: returns the container plus a new file written at the given path.

WithNewFile

Before:

let textFile = fs.openSync("myTextFile", "w")
fs.writeFileSync(textFile, "my text content")

let packageFile = await client
    .host()
    .workdir(undefined, ["myTextFile"])
    .id()

await client
    .container()
    .from("node")
    .withMountedDirectory("/tmp/filedir", packageFile.id)
    .exec([ "cat", "/tmp/filedir/myTextFile" ])
    .stdout()
    .contents()

After:

await client
    .container()
    .from("node")
    .withNewFile("/tmp/filedir/myTextFile", { contents: "my text content" })
    .withExec([ "cat", "/tmp/filedir/myTextFile" ])
    .stdout()

Read the SDK documentation

We believe these changes bring the overall experience of using the SDK closer to what Node.js developers expect and use elsewhere, and also result in shorter and more readable code.

Thank you to the Dagger Community for your continuous and quick feedback. We look forward to releasing more features and documentation soon! In the meanwhile, if you have feedback or would like to suggest new features or documentation, let us know on Discord or create a GitHub issue.


Get Involved With the community

Discover what our community is doing, and join the conversation on Discord & GitHub to help shape the evolution of Dagger.

Subscribe to our newsletter

Get Involved With the community

Discover what our community is doing, and join the conversation on Discord & GitHub to help shape the evolution of Dagger.

Subscribe to our newsletter

Get Involved With the community

Discover what our community is doing, and join the conversation on Discord & GitHub to help shape the evolution of Dagger.

Subscribe to our newsletter