All Projects → hashicorp → Go Argmapper

hashicorp / Go Argmapper

Licence: mpl-2.0
A runtime dependency-injection library for Go that supports automatically chaining conversion functions to reach desired input and output types.

Programming Languages

go
31211 projects - #10 most used programming language
golang
3204 projects
reflection
70 projects

Projects that are alternatives of or similar to Go Argmapper

Marinator
Delicious Dependency Injection
Stars: ✭ 79 (-21.78%)
Mutual labels:  dependency-injection
Jab
C# Source Generator based dependency injection container implementation.
Stars: ✭ 87 (-13.86%)
Mutual labels:  dependency-injection
Bootique
Bootique is a minimally opinionated platform for modern runnable Java apps.
Stars: ✭ 1,326 (+1212.87%)
Mutual labels:  dependency-injection
Price Tracker
Price Tracking Application - An experimental Kotlin Android project with complex android app requirements.
Stars: ✭ 80 (-20.79%)
Mutual labels:  dependency-injection
Fastify Decorators
Set of Typescript decorators to build Fastify server with controllers, services and hooks
Stars: ✭ 85 (-15.84%)
Mutual labels:  dependency-injection
Container Ioc
Inversion of Control container & Dependency Injection for Javascript and Node.js apps powered by Typescript.
Stars: ✭ 89 (-11.88%)
Mutual labels:  dependency-injection
Dikit
Dependency Injection Framework for Swift, inspired by KOIN.
Stars: ✭ 77 (-23.76%)
Mutual labels:  dependency-injection
Momentum
MVC pattern for flutter. Works as state management, dependency injection and service locator.
Stars: ✭ 99 (-1.98%)
Mutual labels:  dependency-injection
Alfa
Effortless React State Management.
Stars: ✭ 86 (-14.85%)
Mutual labels:  dependency-injection
Syrinj
Simpler dependency injection for Unity3D
Stars: ✭ 91 (-9.9%)
Mutual labels:  dependency-injection
Fluent Symfony
Fluent configuration for Symfony
Stars: ✭ 80 (-20.79%)
Mutual labels:  dependency-injection
Getting Started Koin Android
Getting started project with a Android & Koin
Stars: ✭ 83 (-17.82%)
Mutual labels:  dependency-injection
Depject
simplest dependency injection
Stars: ✭ 90 (-10.89%)
Mutual labels:  dependency-injection
Go Web
A new Golang MVC Framework. Like Laravel... but faster!
Stars: ✭ 79 (-21.78%)
Mutual labels:  dependency-injection
Agentframework
An elegant & efficient TypeScript metaprogramming API to build software agents
Stars: ✭ 97 (-3.96%)
Mutual labels:  dependency-injection
Python Dependency Injector
Dependency injection framework for Python
Stars: ✭ 1,203 (+1091.09%)
Mutual labels:  dependency-injection
Datakernel
Alternative Java platform, built from the ground up - with its own async I/O core and DI. Ultra high-performance, simple and minimalistic - redefines server-side programming, web-development and highload!
Stars: ✭ 87 (-13.86%)
Mutual labels:  dependency-injection
No Framework Tutorial
A small tutorial to show how to create a PHP application without a framework.
Stars: ✭ 1,357 (+1243.56%)
Mutual labels:  dependency-injection
Autofac.extensions.dependencyinjection
Autofac implementation of the interfaces in Microsoft.Extensions.DependencyInjection.Abstractions, the .NET Core dependency injection abstraction.
Stars: ✭ 98 (-2.97%)
Mutual labels:  dependency-injection
Mvpandroid
Sample app to demonstrate MVP (Model - View - Presenter) architecture in android
Stars: ✭ 91 (-9.9%)
Mutual labels:  dependency-injection

go-argmapper Godoc

go-argmapper is a dependency-injection library for Go that supports automatically chaining conversion functions to reach desired results. go-argmapper is designed for runtime, reflection-based dependency injection.

API Status: Mostly Stable. We have released HashiCorp products using this library successfully, so we don't think the API will change significantly. For the time being, we're retaining the 0.x version numbers to note that we may still change the API and to recognize that the library has only been used in the real world for a short period of time.

Features

Named parameter matching. go-argmapper can match on named arguments, so you can say that from int is different from to int when calling the same function.

Typed parameter matching. go-argmapper can match on types, including interfaces and interface implementations. This enables the common dependency-injection pattern of fulfilling an interface.

"Subtype" labels for overloaded types. Values can be labeled with a "subtype" key (a string) for more fine-grained matching. A real-world use case of this is protobuf Any values. The subtype of these values can be the protobuf message name. This enables separating name, type, and subtype for more fine-grained matching.

Automatic conversion function chaining. You can configure multiple "conversion functions" that can take some set of values and return another set of values and go-argmapper will automatically call them in the correct order if necessary to reach your desired function parameter types.

Function redefinition in terms of certain types. Functions can be "redefined" to take as input and/or output values that match user-provided filters. go-argmapper will automatically call proper conversion functions to reach the target function.

Type conversion API. In addition to function calling, you can use the automatic conversion function chaining to convert some input values to any target value. go-argmapper will tell you (via an error) if this is not possible.

Examples

Basic Dependency Injection

The example below shows common, basic dependency injection.

// This is our target function. It wants some Writer implementation.
target, err := argmapper.NewFunc(func(w io.Writer) {
	// ... use the writer ...
})

// This is a provider that provides our io.Writer. You can imagine that
// this may differ between test/prod, configs, etc.
provider := func() io.Writer { return bytes.NewBuffer(nil) }

// Call our function. This will call our provider to create an io.Writer
// and then call our target function.
result := target.Call(argmapper.Converter(provider))
if result.Err() != nil {
	panic(result.Err())
}

The key thing happening here is that we're registering the provider function as a "converter." argmapper will automatically find some converter to provide any values we're looking for.

Named and Typed Values

The example below shows both named and typed parameters in use.

target, err := argmapper.NewFunc(func(input struct {
	// This tells argmapper to fill the values in this struct rather
	// than provide a value for the entire struct.
	argmapper.Struct

	A int
	B int
	Prefix string
}) string {
	return fmt.Sprintf("%s: %d", in.Prefix, in.A*in.B)
})

result := target.Call(
	argmapper.Named("a", 21),
	argmapper.Named("b", 2),
	argmapper.Typed("our value is"),
)
if result.Err() != nil {
	panic(result.Err())
}

// This prints: "our value is: 42"
println(result.Out(0).(string))

Both A and B are of the same type, but are matched on their names. This lets us get the desired value of 42, rather than 21*21, 2*2, etc.

Note that Prefix is a named parameter, but we don't provide any inputs matching that name. In this case, argmapper by default falls back to treating it as a typed parameter, allowing our typed string input to match.

Explicitly Typed Values

The previous example showed Prefix implicitly using a typed-only match since there was no input named "Prefix". You can also explictly note that the name doesn't matter in two ways.

First, you can use struct tags:

target, err := argmapper.NewFunc(func(input struct {
	// This tells argmapper to fill the values in this struct rather
	// than provide a value for the entire struct.
	argmapper.Struct

	A int
	B int
	Prefix string `argmapper:",typeOnly"`
}) string {
	return fmt.Sprintf("%s: %d", in.Prefix, in.A*in.B)
})

You can also use a non-struct input. Go reflection doesn't reveal function parameter names so all function parameters are by definition type only:

target, err := argmapper.NewFunc(func(string) {})

You can mix and match named and typed parameters.

Conversion Function Chaining

The example below shows how conversion functions are automatically chained as necessary to reach your desired function.

// Trivial function that takes a string and just returns it.
target, err := argmapper.NewFunc(func(v string) string { return v })

result := target.Call(
	// "false" value
	argmapper.Typed(false),

	// bool to int
	argmapper.Converter(func(v bool) int {
		if v {
			return 1
		}

		return 0
	}),

	// int to string
	argmapper.Converter(func(v int) string {
		return strconv.Itoa(v)
	}),
)
if result.Err() != nil {
	// If we didn't have converters necessary to get us from bool => int => string
	// then this would fail.
	panic(result.Err())
}

// Prints "0"
println(result.Out(0).(string))

Typed converters preserve the name of their arguments. If the above input was Named("foo", false) rather than typed, then the name "foo" would be attached both the string and int values generated in case any target functions requested a named parameter. In the case of this example, the name is carried through but carries no consequence since the final target function is just a typed parameter.

Conversion Function Cycles

Cycles in conversion functions are completely allowed. The example below behaves as you would expect. This is a simple direct cycle, more complex cycles from chaining multiple converters will also behave correctly. This lets you register complex sets of bidirectional conversion functions with ease.

// Trivial function that takes a string and just returns it.
target, err := argmapper.NewFunc(func(v string) string { return v })

result := target.Call(
	argmapper.Typed(12),
	argmapper.Converter(func(v int) string { return strconv.Itoa(v) }),
	argmapper.Converter(func(v string) (int, error) { return strconv.Atoi(v) }),
)
if result.Err() != nil {
	// If we didn't have converters necessary to get us from bool => int => string
	// then this would fail.
	panic(result.Err())
}

// Prints "12"
println(result.Out(0).(string))

Conversion Errors

The example above has a converter that returns (int, error). If the final return type of a converter is error, go-argmapper treats that as a special value signaling if the conversion succeeded or failed.

If conversion fails, the target function call fails and the error is returned to the user.

In the future, we plan on retrying via other possible conversion paths if they are available.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].