1663618320
In today's post we will learn about 10 Favorite Go Libraries for Working with UUIDs.
What is a UUID?
A UUID – that’s short for Universally Unique IDentifier, by the way – is a 36-character alphanumeric string that can be used to identify information (such as a table row).
Here is one example of a UUID: acde070d-8c4c-4f0d-9d8a-162843c10333
UUIDs are widely used in part because they are highly likely to be unique globally, meaning that not only is our row’s UUID unique in our database table, it’s probably the only row with that UUID in any system anywhere.
(Technically, it’s not impossible that the same UUID we generate could be used somewhere else, but with 340,282,366,920,938,463,463,374,607,431,768,211,456 different possible UUIDs out there, the chances are very slim).
Table of contents:
Generate and Parse RFC4122 compliant V4 UUIDs.
An example of generating a v4 UUID and outputting it
import (
"fmt"
"github.com/jakehl/goid"
)
func main() {
v4UUID := goid.NewV4UUID()
fmt.Println(v4UUID)
}
The API docs can be viewed here or generated with godoc.
Generate cryptographically secure random string IDs with just one allocation.
Gouid - Use Gouid to create cryptographically secure random IDs. IDs can be byte slices or strings, both generated with just one allocation (see benchmarks below).
package main
import (
"fmt"
"github.com/twharmon/gouid"
)
func main() {
a := gouid.String(8, gouid.LowerCaseAlphaNum)
fmt.Println(a) // mp6nq37p
b := gouid.String(16, gouid.MixedCaseAlpha)
fmt.Println(b) // hCSoemLKaUQtoXgh
c := gouid.Bytes(16)
fmt.Println(c) // [244 188 217 137 122 245 94 126 80 119 87 170 6 178 228 179]
}
BenchmarkString8 120 ns/op 8 B/op 1 allocs/op
BenchmarkString16 197 ns/op 16 B/op 1 allocs/op
BenchmarkString32 345 ns/op 32 B/op 1 allocs/op
BenchmarkBytes8 67.3 ns/op 8 B/op 1 allocs/op
BenchmarkBytes16 94.4 ns/op 16 B/op 1 allocs/op
BenchmarkBytes32 143 ns/op 32 B/op 1 allocs/op
Make a pull request.
A tiny and efficient Go unique string ID generator.
(A-Za-z0-9_-)
. So ID size was reduced from 36 to 21 symbols.id, err := nanoid.New() //> "i25_rX9zwDdDn7Sg-ZoaH"
if err != nil {
log.Fatalln(err)
}
Once Go is installed, run the following command to get Nano ID.
go get github.com/aidarkhanov/nanoid/v2
The package reference is located at pkg.go.dev/github.com/aidarkhanov/nanoid/v2.
Compact, sortable and fast unique IDs with embedded metadata.
A spec for unique IDs in distributed systems based on the Snowflake design, i.e. a coordination-based ID variant. It aims to be friendly to both machines and humans, compact, versatile and fast.
This repository contains a Go package for generating such IDs.
sno comes with a package-level generator on top of letting you configure your own generators.
Generating a new ID using the defaults takes no more than importing the package and:
id := sno.New(0)
Where 0
is the ➜ Metabyte.
The global generator is immutable and private. It's therefore also not possible to restore it using a Snapshot. Its Partition is based on time and changes across restarts.
As soon as you run more than 1 generator, you should start coordinating the creation of Generators to actually guarantee a collision-free ride. This applies to all specs of the Snowflake variant.
Partitions are one of several friends you have to get you those guarantees. A Partition is 2 bytes. What they mean and how you define them is up to you.
generator, err := sno.NewGenerator(&sno.GeneratorSnapshot{
Partition: sno.Partition{'A', 10}
}, nil)
Multiple generators can share a partition by dividing the sequence pool between them (➜ Sequence sharding).
Snapshots happen to serve both as configuration and a means of saving and restoring generator data. They are optional - simply pass nil
to NewGenerator()
, to get a Generator with sane defaults and a unique (in-process) Partition.
Snapshots can be taken at runtime:
s := generator.Snapshot()
This exposes most of a Generator's internal bookkeeping data. In an ideal world where programmers are not lazy until their system runs into an edge case - you'd persist that snapshot across restarts and restore generators instead of just creating them from scratch each time. This will keep you safe both if a large clock drift happens during the restart -- or before, and you just happen to come back online again "in the past", relative to IDs that had already been generated.
A snapshot is a sample in time - it will very quickly get stale. Only take snapshots meant for restoring them later when generators are already offline - or for metrics purposes when online.
Go implementation of ULID (Universally Unique Lexicographically Sortable Identifier).
A GUID/UUID can be suboptimal for many use-cases because:
A ULID however:
This package requires Go modules.
go get github.com/oklog/ulid/v2
ULIDs are constructed from two things: a timestamp with millisecond precision, and some random data.
Timestamps are modeled as uint64 values representing a Unix time in milliseconds. They can be produced by passing a time.Time to ulid.Timestamp, or by calling time.Time.UnixMilli and converting the returned value to uint64
.
Random data is taken from a provided io.Reader. This design allows for greater flexibility when choosing trade-offs, but can be a bit confusing to newcomers.
If you just want to generate a ULID and don't (yet) care about details like performance, cryptographic security, monotonicity, etc., use the ulid.Make helper function. This function calls time.Now to get a timestamp, and uses a source of entropy which is process-global, pseudo-random), and monotonic).
println(ulid.Make())
// 01G65Z755AFWAKHE12NY0CQ9FH
More advanced use cases should utilize ulid.New.
entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
ms := ulid.Timestamp(time.Now())
println(ulid.New(ms, entropy))
// 01G65Z755AFWAKHE12NY0CQ9FH
Care should be taken when providing a source of entropy.
The above example utilizes math/rand.Rand, which is not safe for concurrent use by multiple goroutines. Consider alternatives such as x/exp/rand. Security-sensitive use cases should always use cryptographically secure entropy provided by crypto/rand.
Performance-sensitive use cases should avoid synchronization when generating IDs. One option is to use a unique source of entropy for each concurrent goroutine, which results in no lock contention, but cannot provide strong guarantees about the random data, and does not provide monotonicity within a given millisecond. One common performance optimization is to pool sources of entropy using a sync.Pool.
Monotonicity is a property that says each ULID is "bigger than" the previous one. ULIDs are automatically monotonic, but only to millisecond precision. ULIDs generated within the same millisecond are ordered by their random component, which means they are by default un-ordered. You can use ulid.MonotonicEntropy or ulid.LockedMonotonicEntropy to create ULIDs that are monotonic within a given millisecond, with caveats. See the documentation for details.
If you don't care about time-based ordering of generated IDs, then there's no reason to use ULIDs! There are many other kinds of IDs that are easier, faster, smaller, etc. Consider UUIDs.
Xid is a globally unique id generator library, ready to be safely used directly in your server code.
Package xid is a globally unique id generator library, ready to safely be used directly in your server code.
Xid uses the Mongo Object ID algorithm to generate globally unique ids with a different serialization (base64) to make it shorter when transported as a string: https://docs.mongodb.org/manual/reference/object-id/
The binary representation of the id is compatible with Mongo 12 bytes Object IDs. The string representation is using base32 hex (w/o padding) for better space efficiency when stored in that form (20 bytes). The hex variant of base32 is used to retain the sortable property of the id.
Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an issue when transported as a string between various systems. Base36 wasn't retained either because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned) and 3/ it would not remain sortable. To validate a base32 xid
, expect a 20 chars long, all lowercase sequence of a
to v
letters and 0
to 9
numbers ([0-9a-v]{20}
).
UUIDs are 16 bytes (128 bits) and 36 chars as string representation. Twitter Snowflake ids are 8 bytes (64 bits) but require machine/data-center configuration and/or central generator servers. xid stands in between with 12 bytes (96 bits) and a more compact URL-safe string representation (20 chars). No configuration or central generator server is required so it can be used directly in server's code.
go get github.com/rs/xid
guid := xid.New()
println(guid.String())
// Output: 9m4e2mr0ui3e8a215n4g
Get xid
embedded info:
guid.Machine()
guid.Pid()
guid.Time()
guid.Counter()
Benchmark against Go Maxim Bublis's UUID.
BenchmarkXID 20000000 91.1 ns/op 32 B/op 1 allocs/op
BenchmarkXID-2 20000000 55.9 ns/op 32 B/op 1 allocs/op
BenchmarkXID-4 50000000 32.3 ns/op 32 B/op 1 allocs/op
BenchmarkUUIDv1 10000000 204 ns/op 48 B/op 1 allocs/op
BenchmarkUUIDv1-2 10000000 160 ns/op 48 B/op 1 allocs/op
BenchmarkUUIDv1-4 10000000 195 ns/op 48 B/op 1 allocs/op
BenchmarkUUIDv4 1000000 1503 ns/op 64 B/op 2 allocs/op
BenchmarkUUIDv4-2 1000000 1427 ns/op 64 B/op 2 allocs/op
BenchmarkUUIDv4-4 1000000 1452 ns/op 64 B/op 2 allocs/op
Note: UUIDv1 requires a global lock, hence the performance degradation as we add more CPUs.
Generate, encode, and decode UUIDs v1 with fast or cryptographic-quality random node identifier.
v1.1.0 Stable: Guaranteed no breaking changes to the API in future v1.x releases. Probably safe to use in production, though provided on "AS IS" basis.
This package is being actively maintained. If you encounter any problems or have any suggestions for improvement, please open an issue. Pull requests are welcome.
Package uuid implements generation and manipulation of UUIDs (v1 defined in RFC 4122).
Version 1 UUIDs are time-based and include a node identifier that can be a MAC address or a random 48-bit value.
This package uses the random approach for the node identifier, setting both the 'multicast' and 'local' bits to make sure the value cannot be confused with a real IEEE 802 address (see section 4.5 of RFC 4122). The initial node identifier is a cryptographic-quality random 46-bit value. The first 30 bits can be set and retrieved with the SetNodeId
and NodeId
functions and method, so that they can be used as a hard-coded instance id. The remaining 16 bits are reserved for increasing the randomness of the UUIDs and to avoid collisions on clock sequence rollovers.
The basic generator New
increments the clock sequence on every call and when the counter rolls over the last 16 bits of the node identifier are regenerated using a PRNG seeded at init()-time with the initial node identifier. This approach sacrifices cryptographic quality for speed and for avoiding depletion of the OS entropy pool (yes, it can and does happen).
The NewCrypto
generator replaces the clock sequence and last 16 bits of the node identifier on each call with cryptographic-quality random values.
go get github.com/agext/uuid
Implementation of Universally Unique Identifier (UUID). Supports both creation and parsing of UUIDs. Actively maintained fork of satori uuid.
Package uuid provides a pure Go implementation of Universally Unique Identifiers (UUID) variant as defined in RFC-4122. This package supports both the creation and parsing of UUIDs in different formats.
This package supports the following UUID versions:
This package also supports experimental Universally Unique Identifier implementations based on a draft RFC that updates RFC-4122
The v6 and v7 IDs are not considered a part of the stable API, and may be subject to behavior or API changes as part of minor releases to this package. They will be updated as the draft RFC changes, and will become stable if and when the draft RFC is accepted.
This project was originally forked from the github.com/satori/go.uuid repository after it appeared to be no longer maintained, while exhibiting critical flaws. We have decided to take over this project to ensure it receives regular maintenance for the benefit of the larger Go community.
We'd like to thank Maxim Bublis for his hard work on the original iteration of the package.
It is recommended to use a package manager like dep
that understands tagged releases of a package, as well as semantic versioning.
If you are unable to make use of a dependency manager with your project, you can use the go get
command to download it directly:
$ go get github.com/gofrs/uuid
Due to subtests not being supported in older versions of Go, this package is only regularly tested against Go 1.7+. This package may work perfectly fine with Go 1.2+, but support for these older versions is not actively maintained.
As of v3.2.0, this repository no longer adopts Go modules, and v3.2.0 no longer has a go.mod
file. As a result, v3.2.0 also drops support for the github.com/gofrs/uuid/v3
import path. Only module-based consumers are impacted. With the v3.2.0 release, all gofrs/uuid consumers should use the github.com/gofrs/uuid
import path.
An existing module-based consumer will continue to be able to build using the github.com/gofrs/uuid/v3
import path using any valid consumer go.mod
that worked prior to the publishing of v3.2.0, but any module-based consumer should start using the github.com/gofrs/uuid
import path when possible and must use the github.com/gofrs/uuid
import path prior to upgrading to v3.2.0.
Please refer to Issue #61 and Issue #66 for more details.
Here is a quick overview of how to use this package. For more detailed documentation, please see the GoDoc Page.
package main
import (
"log"
"github.com/gofrs/uuid"
)
// Create a Version 4 UUID, panicking on error.
// Use this form to initialize package-level variables.
var u1 = uuid.Must(uuid.NewV4())
func main() {
// Create a Version 4 UUID.
u2, err := uuid.NewV4()
if err != nil {
log.Fatalf("failed to generate UUID: %v", err)
}
log.Printf("generated Version 4 UUID %v", u2)
// Parse a UUID from a string.
s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
u3, err := uuid.FromString(s)
if err != nil {
log.Fatalf("failed to parse UUID %q: %v", s, err)
}
log.Printf("successfully parsed UUID %v", u3)
}
Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
The uuid package generates and inspects UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named code.google.com/p/go-uuid). It differs from these earlier packages in that a UUID is a 16 byte array rather than a byte slice. One loss due to this change is the ability to represent an invalid UUID (vs a NIL UUID).
Install
go get github.com/google/uuid
Documentation
Full go doc
style documentation for the package can be viewed online without installing this package by using the GoDoc site here: http://pkg.go.dev/github.com/google/uuid
An extremely fast unique number generator, 10-135 times faster than UUID.
Overview
Benchmarks
BenchmarkWUID 187500764 6.38 ns/op 0 B/op 0 allocs/op
BenchmarkRand 97180698 12.2 ns/op 0 B/op 0 allocs/op
BenchmarkTimestamp 17126514 67.8 ns/op 0 B/op 0 allocs/op
BenchmarkUUID_V1 11986558 99.6 ns/op 0 B/op 0 allocs/op
BenchmarkUUID_V2 12017754 101 ns/op 0 B/op 0 allocs/op
BenchmarkUUID_V3 4925020 242 ns/op 144 B/op 4 allocs/op
BenchmarkUUID_V4 14184271 84.1 ns/op 16 B/op 1 allocs/op
BenchmarkUUID_V5 4277338 274 ns/op 176 B/op 4 allocs/op
BenchmarkRedis 35462 35646 ns/op 176 B/op 5 allocs/op
BenchmarkSnowflake 4931476 244 ns/op 0 B/op 0 allocs/op
BenchmarkULID 8410358 141 ns/op 16 B/op 1 allocs/op
BenchmarkXID 15000969 79.2 ns/op 0 B/op 0 allocs/op
BenchmarkShortID 1738039 698.9 ns/op 311 B/op 11 allocs/op
Features
Install
go get -u github.com/edwingeng/wuid
Usage examples
import "github.com/edwingeng/wuid/redis/wuid"
newClient := func() (redis.Cmdable, bool, error) {
var client redis.Cmdable
// ...
return client, true, nil
}
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28FromRedis(newClient, "wuid")
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
import "github.com/edwingeng/wuid/mysql/wuid"
newDB := func() (*sql.DB, bool, error) {
var db *sql.DB
// ...
return db, true, nil
}
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28FromMysql(newDB, "wuid")
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
Thank you for following this article.
Universally Unique Identifiers (UUID/GUID) // Game Engine series
1663618320
In today's post we will learn about 10 Favorite Go Libraries for Working with UUIDs.
What is a UUID?
A UUID – that’s short for Universally Unique IDentifier, by the way – is a 36-character alphanumeric string that can be used to identify information (such as a table row).
Here is one example of a UUID: acde070d-8c4c-4f0d-9d8a-162843c10333
UUIDs are widely used in part because they are highly likely to be unique globally, meaning that not only is our row’s UUID unique in our database table, it’s probably the only row with that UUID in any system anywhere.
(Technically, it’s not impossible that the same UUID we generate could be used somewhere else, but with 340,282,366,920,938,463,463,374,607,431,768,211,456 different possible UUIDs out there, the chances are very slim).
Table of contents:
Generate and Parse RFC4122 compliant V4 UUIDs.
An example of generating a v4 UUID and outputting it
import (
"fmt"
"github.com/jakehl/goid"
)
func main() {
v4UUID := goid.NewV4UUID()
fmt.Println(v4UUID)
}
The API docs can be viewed here or generated with godoc.
Generate cryptographically secure random string IDs with just one allocation.
Gouid - Use Gouid to create cryptographically secure random IDs. IDs can be byte slices or strings, both generated with just one allocation (see benchmarks below).
package main
import (
"fmt"
"github.com/twharmon/gouid"
)
func main() {
a := gouid.String(8, gouid.LowerCaseAlphaNum)
fmt.Println(a) // mp6nq37p
b := gouid.String(16, gouid.MixedCaseAlpha)
fmt.Println(b) // hCSoemLKaUQtoXgh
c := gouid.Bytes(16)
fmt.Println(c) // [244 188 217 137 122 245 94 126 80 119 87 170 6 178 228 179]
}
BenchmarkString8 120 ns/op 8 B/op 1 allocs/op
BenchmarkString16 197 ns/op 16 B/op 1 allocs/op
BenchmarkString32 345 ns/op 32 B/op 1 allocs/op
BenchmarkBytes8 67.3 ns/op 8 B/op 1 allocs/op
BenchmarkBytes16 94.4 ns/op 16 B/op 1 allocs/op
BenchmarkBytes32 143 ns/op 32 B/op 1 allocs/op
Make a pull request.
A tiny and efficient Go unique string ID generator.
(A-Za-z0-9_-)
. So ID size was reduced from 36 to 21 symbols.id, err := nanoid.New() //> "i25_rX9zwDdDn7Sg-ZoaH"
if err != nil {
log.Fatalln(err)
}
Once Go is installed, run the following command to get Nano ID.
go get github.com/aidarkhanov/nanoid/v2
The package reference is located at pkg.go.dev/github.com/aidarkhanov/nanoid/v2.
Compact, sortable and fast unique IDs with embedded metadata.
A spec for unique IDs in distributed systems based on the Snowflake design, i.e. a coordination-based ID variant. It aims to be friendly to both machines and humans, compact, versatile and fast.
This repository contains a Go package for generating such IDs.
sno comes with a package-level generator on top of letting you configure your own generators.
Generating a new ID using the defaults takes no more than importing the package and:
id := sno.New(0)
Where 0
is the ➜ Metabyte.
The global generator is immutable and private. It's therefore also not possible to restore it using a Snapshot. Its Partition is based on time and changes across restarts.
As soon as you run more than 1 generator, you should start coordinating the creation of Generators to actually guarantee a collision-free ride. This applies to all specs of the Snowflake variant.
Partitions are one of several friends you have to get you those guarantees. A Partition is 2 bytes. What they mean and how you define them is up to you.
generator, err := sno.NewGenerator(&sno.GeneratorSnapshot{
Partition: sno.Partition{'A', 10}
}, nil)
Multiple generators can share a partition by dividing the sequence pool between them (➜ Sequence sharding).
Snapshots happen to serve both as configuration and a means of saving and restoring generator data. They are optional - simply pass nil
to NewGenerator()
, to get a Generator with sane defaults and a unique (in-process) Partition.
Snapshots can be taken at runtime:
s := generator.Snapshot()
This exposes most of a Generator's internal bookkeeping data. In an ideal world where programmers are not lazy until their system runs into an edge case - you'd persist that snapshot across restarts and restore generators instead of just creating them from scratch each time. This will keep you safe both if a large clock drift happens during the restart -- or before, and you just happen to come back online again "in the past", relative to IDs that had already been generated.
A snapshot is a sample in time - it will very quickly get stale. Only take snapshots meant for restoring them later when generators are already offline - or for metrics purposes when online.
Go implementation of ULID (Universally Unique Lexicographically Sortable Identifier).
A GUID/UUID can be suboptimal for many use-cases because:
A ULID however:
This package requires Go modules.
go get github.com/oklog/ulid/v2
ULIDs are constructed from two things: a timestamp with millisecond precision, and some random data.
Timestamps are modeled as uint64 values representing a Unix time in milliseconds. They can be produced by passing a time.Time to ulid.Timestamp, or by calling time.Time.UnixMilli and converting the returned value to uint64
.
Random data is taken from a provided io.Reader. This design allows for greater flexibility when choosing trade-offs, but can be a bit confusing to newcomers.
If you just want to generate a ULID and don't (yet) care about details like performance, cryptographic security, monotonicity, etc., use the ulid.Make helper function. This function calls time.Now to get a timestamp, and uses a source of entropy which is process-global, pseudo-random), and monotonic).
println(ulid.Make())
// 01G65Z755AFWAKHE12NY0CQ9FH
More advanced use cases should utilize ulid.New.
entropy := rand.New(rand.NewSource(time.Now().UnixNano()))
ms := ulid.Timestamp(time.Now())
println(ulid.New(ms, entropy))
// 01G65Z755AFWAKHE12NY0CQ9FH
Care should be taken when providing a source of entropy.
The above example utilizes math/rand.Rand, which is not safe for concurrent use by multiple goroutines. Consider alternatives such as x/exp/rand. Security-sensitive use cases should always use cryptographically secure entropy provided by crypto/rand.
Performance-sensitive use cases should avoid synchronization when generating IDs. One option is to use a unique source of entropy for each concurrent goroutine, which results in no lock contention, but cannot provide strong guarantees about the random data, and does not provide monotonicity within a given millisecond. One common performance optimization is to pool sources of entropy using a sync.Pool.
Monotonicity is a property that says each ULID is "bigger than" the previous one. ULIDs are automatically monotonic, but only to millisecond precision. ULIDs generated within the same millisecond are ordered by their random component, which means they are by default un-ordered. You can use ulid.MonotonicEntropy or ulid.LockedMonotonicEntropy to create ULIDs that are monotonic within a given millisecond, with caveats. See the documentation for details.
If you don't care about time-based ordering of generated IDs, then there's no reason to use ULIDs! There are many other kinds of IDs that are easier, faster, smaller, etc. Consider UUIDs.
Xid is a globally unique id generator library, ready to be safely used directly in your server code.
Package xid is a globally unique id generator library, ready to safely be used directly in your server code.
Xid uses the Mongo Object ID algorithm to generate globally unique ids with a different serialization (base64) to make it shorter when transported as a string: https://docs.mongodb.org/manual/reference/object-id/
The binary representation of the id is compatible with Mongo 12 bytes Object IDs. The string representation is using base32 hex (w/o padding) for better space efficiency when stored in that form (20 bytes). The hex variant of base32 is used to retain the sortable property of the id.
Xid doesn't use base64 because case sensitivity and the 2 non alphanum chars may be an issue when transported as a string between various systems. Base36 wasn't retained either because 1/ it's not standard 2/ the resulting size is not predictable (not bit aligned) and 3/ it would not remain sortable. To validate a base32 xid
, expect a 20 chars long, all lowercase sequence of a
to v
letters and 0
to 9
numbers ([0-9a-v]{20}
).
UUIDs are 16 bytes (128 bits) and 36 chars as string representation. Twitter Snowflake ids are 8 bytes (64 bits) but require machine/data-center configuration and/or central generator servers. xid stands in between with 12 bytes (96 bits) and a more compact URL-safe string representation (20 chars). No configuration or central generator server is required so it can be used directly in server's code.
go get github.com/rs/xid
guid := xid.New()
println(guid.String())
// Output: 9m4e2mr0ui3e8a215n4g
Get xid
embedded info:
guid.Machine()
guid.Pid()
guid.Time()
guid.Counter()
Benchmark against Go Maxim Bublis's UUID.
BenchmarkXID 20000000 91.1 ns/op 32 B/op 1 allocs/op
BenchmarkXID-2 20000000 55.9 ns/op 32 B/op 1 allocs/op
BenchmarkXID-4 50000000 32.3 ns/op 32 B/op 1 allocs/op
BenchmarkUUIDv1 10000000 204 ns/op 48 B/op 1 allocs/op
BenchmarkUUIDv1-2 10000000 160 ns/op 48 B/op 1 allocs/op
BenchmarkUUIDv1-4 10000000 195 ns/op 48 B/op 1 allocs/op
BenchmarkUUIDv4 1000000 1503 ns/op 64 B/op 2 allocs/op
BenchmarkUUIDv4-2 1000000 1427 ns/op 64 B/op 2 allocs/op
BenchmarkUUIDv4-4 1000000 1452 ns/op 64 B/op 2 allocs/op
Note: UUIDv1 requires a global lock, hence the performance degradation as we add more CPUs.
Generate, encode, and decode UUIDs v1 with fast or cryptographic-quality random node identifier.
v1.1.0 Stable: Guaranteed no breaking changes to the API in future v1.x releases. Probably safe to use in production, though provided on "AS IS" basis.
This package is being actively maintained. If you encounter any problems or have any suggestions for improvement, please open an issue. Pull requests are welcome.
Package uuid implements generation and manipulation of UUIDs (v1 defined in RFC 4122).
Version 1 UUIDs are time-based and include a node identifier that can be a MAC address or a random 48-bit value.
This package uses the random approach for the node identifier, setting both the 'multicast' and 'local' bits to make sure the value cannot be confused with a real IEEE 802 address (see section 4.5 of RFC 4122). The initial node identifier is a cryptographic-quality random 46-bit value. The first 30 bits can be set and retrieved with the SetNodeId
and NodeId
functions and method, so that they can be used as a hard-coded instance id. The remaining 16 bits are reserved for increasing the randomness of the UUIDs and to avoid collisions on clock sequence rollovers.
The basic generator New
increments the clock sequence on every call and when the counter rolls over the last 16 bits of the node identifier are regenerated using a PRNG seeded at init()-time with the initial node identifier. This approach sacrifices cryptographic quality for speed and for avoiding depletion of the OS entropy pool (yes, it can and does happen).
The NewCrypto
generator replaces the clock sequence and last 16 bits of the node identifier on each call with cryptographic-quality random values.
go get github.com/agext/uuid
Implementation of Universally Unique Identifier (UUID). Supports both creation and parsing of UUIDs. Actively maintained fork of satori uuid.
Package uuid provides a pure Go implementation of Universally Unique Identifiers (UUID) variant as defined in RFC-4122. This package supports both the creation and parsing of UUIDs in different formats.
This package supports the following UUID versions:
This package also supports experimental Universally Unique Identifier implementations based on a draft RFC that updates RFC-4122
The v6 and v7 IDs are not considered a part of the stable API, and may be subject to behavior or API changes as part of minor releases to this package. They will be updated as the draft RFC changes, and will become stable if and when the draft RFC is accepted.
This project was originally forked from the github.com/satori/go.uuid repository after it appeared to be no longer maintained, while exhibiting critical flaws. We have decided to take over this project to ensure it receives regular maintenance for the benefit of the larger Go community.
We'd like to thank Maxim Bublis for his hard work on the original iteration of the package.
It is recommended to use a package manager like dep
that understands tagged releases of a package, as well as semantic versioning.
If you are unable to make use of a dependency manager with your project, you can use the go get
command to download it directly:
$ go get github.com/gofrs/uuid
Due to subtests not being supported in older versions of Go, this package is only regularly tested against Go 1.7+. This package may work perfectly fine with Go 1.2+, but support for these older versions is not actively maintained.
As of v3.2.0, this repository no longer adopts Go modules, and v3.2.0 no longer has a go.mod
file. As a result, v3.2.0 also drops support for the github.com/gofrs/uuid/v3
import path. Only module-based consumers are impacted. With the v3.2.0 release, all gofrs/uuid consumers should use the github.com/gofrs/uuid
import path.
An existing module-based consumer will continue to be able to build using the github.com/gofrs/uuid/v3
import path using any valid consumer go.mod
that worked prior to the publishing of v3.2.0, but any module-based consumer should start using the github.com/gofrs/uuid
import path when possible and must use the github.com/gofrs/uuid
import path prior to upgrading to v3.2.0.
Please refer to Issue #61 and Issue #66 for more details.
Here is a quick overview of how to use this package. For more detailed documentation, please see the GoDoc Page.
package main
import (
"log"
"github.com/gofrs/uuid"
)
// Create a Version 4 UUID, panicking on error.
// Use this form to initialize package-level variables.
var u1 = uuid.Must(uuid.NewV4())
func main() {
// Create a Version 4 UUID.
u2, err := uuid.NewV4()
if err != nil {
log.Fatalf("failed to generate UUID: %v", err)
}
log.Printf("generated Version 4 UUID %v", u2)
// Parse a UUID from a string.
s := "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
u3, err := uuid.FromString(s)
if err != nil {
log.Fatalf("failed to parse UUID %q: %v", s, err)
}
log.Printf("successfully parsed UUID %v", u3)
}
Go package for UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
The uuid package generates and inspects UUIDs based on RFC 4122 and DCE 1.1: Authentication and Security Services.
This package is based on the github.com/pborman/uuid package (previously named code.google.com/p/go-uuid). It differs from these earlier packages in that a UUID is a 16 byte array rather than a byte slice. One loss due to this change is the ability to represent an invalid UUID (vs a NIL UUID).
Install
go get github.com/google/uuid
Documentation
Full go doc
style documentation for the package can be viewed online without installing this package by using the GoDoc site here: http://pkg.go.dev/github.com/google/uuid
An extremely fast unique number generator, 10-135 times faster than UUID.
Overview
Benchmarks
BenchmarkWUID 187500764 6.38 ns/op 0 B/op 0 allocs/op
BenchmarkRand 97180698 12.2 ns/op 0 B/op 0 allocs/op
BenchmarkTimestamp 17126514 67.8 ns/op 0 B/op 0 allocs/op
BenchmarkUUID_V1 11986558 99.6 ns/op 0 B/op 0 allocs/op
BenchmarkUUID_V2 12017754 101 ns/op 0 B/op 0 allocs/op
BenchmarkUUID_V3 4925020 242 ns/op 144 B/op 4 allocs/op
BenchmarkUUID_V4 14184271 84.1 ns/op 16 B/op 1 allocs/op
BenchmarkUUID_V5 4277338 274 ns/op 176 B/op 4 allocs/op
BenchmarkRedis 35462 35646 ns/op 176 B/op 5 allocs/op
BenchmarkSnowflake 4931476 244 ns/op 0 B/op 0 allocs/op
BenchmarkULID 8410358 141 ns/op 16 B/op 1 allocs/op
BenchmarkXID 15000969 79.2 ns/op 0 B/op 0 allocs/op
BenchmarkShortID 1738039 698.9 ns/op 311 B/op 11 allocs/op
Features
Install
go get -u github.com/edwingeng/wuid
Usage examples
import "github.com/edwingeng/wuid/redis/wuid"
newClient := func() (redis.Cmdable, bool, error) {
var client redis.Cmdable
// ...
return client, true, nil
}
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28FromRedis(newClient, "wuid")
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
import "github.com/edwingeng/wuid/mysql/wuid"
newDB := func() (*sql.DB, bool, error) {
var db *sql.DB
// ...
return db, true, nil
}
// Setup
g := NewWUID("default", nil)
_ = g.LoadH28FromMysql(newDB, "wuid")
// Generate
for i := 0; i < 10; i++ {
fmt.Printf("%#016x\n", g.Next())
}
Thank you for following this article.
Universally Unique Identifiers (UUID/GUID) // Game Engine series
1599854400
Go announced Go 1.15 version on 11 Aug 2020. Highlighted updates and features include Substantial improvements to the Go linker, Improved allocation for small objects at high core counts, X.509 CommonName deprecation, GOPROXY supports skipping proxies that return errors, New embedded tzdata package, Several Core Library improvements and more.
As Go promise for maintaining backward compatibility. After upgrading to the latest Go 1.15 version, almost all existing Golang applications or programs continue to compile and run as older Golang version.
#go #golang #go 1.15 #go features #go improvement #go package #go new features
1597848999
Created by Google researchers, Go is a popular open-source programming language. The language includes many intuitive features, including a garbage collector, cross-platform, efficient concurrency, among others.
According to the Stack Overflow Developer Survey 2020, Go language is not only the fifth most loved programming language but also fetches the programmers the third-highest salary among other languages.
Below here, we list down the top machine learning libraries in Go language.
#opinions #go language #google ml tools #machine learning libraries #ml libraries #ml libraries in go
1614329473
G Suite is one of the Google products, developed form of Google Apps. It is a single platform to hold cloud computing, collaboration tools, productivity, software, and products. While using it, many a time, it’s not working, and users have a question– How to fix G Suite not working on iPhone? It can be resolved easily by restarting the device, and if unable to do so, you can reach our specialists whenever you want.
For more details: https://contactforhelp.com/blog/how-to-fix-the-g-suite-email-not-working-issue/
#g suite email not working #g suite email not working on iphone #g suite email not working on android #suite email not working on windows 10 #g suite email not working on mac #g suite email not syncing
1663248360
In today's post we will learn about 10 Best Libraries for Working with Forms in Go.
What is Working with Forms?
Forms are used to receive information from the user. Forms are commonly used to allow users to register on a Web site, to log in to a Web site, to order a product, and to send feedback. In search engines, forms are used to accept the keywords for search.
The <form> tag is used to create a form. An HTML from starts with <form> and ends with </form> tag. Forms contain many types of form elements, such as text boxes, radio buttons, check boxes, buttons and drop-down lists.
The form has a special element, which is submit button, which will submit the entries of a form to a server application to process the entries. Each element in the form is assigned a name using the name attribute. Users enter values into the text boxes, or make selections from the radio buttons, check boxes, and drop down lists. The values they enter or select are passed with the name of the corresponding form element to the Web server.
Table of contents:
Bind is a library for binding HTTP request parameters to Go objects.
It comes with binders for all values, time.Time, arbitrary structs, and slices. In particular, binding functions are provided for the following types:
Callers may also hook into the process and provide a custom binding function.
This example binds data from embedded URL arguments, the query string, and a posted form.
POST /accounts/:accountId/users/?op=UPDATE
<form>
<input name="user.Id">
<input name="user.Name">
<input name="user.Phones[0].Label">
<input name="user.Phones[0].Number">
<input name="user.Phones[1].Label">
<input name="user.Phones[1].Number">
<input name="user.Labels[]">
<input name="user.Labels[]">
</form>
type Phone struct { Label, Number string }
type User struct {
Id uint32
Phones []Phone
Labels []string
}
var (
params = mux.Vars(req) // embedded URL args
id uint32
op string
user User
)
handleErrors(
bind.Map(params).Field(&id, "accountId"),
bind.Request(req).Field(&op, "op")
bind.Request(req).Field(&user, "user"),
)
Booleans are converted to Go by comparing against the following strings:
TRUE: "true", "1", "on"
FALSE: "false", "0", ""
The "on" / "" syntax is supported as the default behavior for HTML checkboxes.
Reflectionless data binding for Go's net/http
net/http
is present (Negroni, gocraft/web, std lib, etc.)package main
import (
"fmt"
"net/http"
"github.com/mholt/binding"
)
// First define a type to hold the data
// (If the data comes from JSON, see: http://mholt.github.io/json-to-go)
type ContactForm struct {
User struct {
ID int
}
Email string
Message string
}
// Then provide a field mapping (pointer receiver is vital)
func (cf *ContactForm) FieldMap(req *http.Request) binding.FieldMap {
return binding.FieldMap{
&cf.User.ID: "user_id",
&cf.Email: "email",
&cf.Message: binding.Field{
Form: "message",
Required: true,
},
}
}
// Now your handlers can stay clean and simple
func handler(resp http.ResponseWriter, req *http.Request) {
contactForm := new(ContactForm)
if errs := binding.Bind(req, contactForm); errs != nil {
http.Error(resp, errs.Error(), http.StatusBadRequest)
return
}
fmt.Fprintf(resp, "From: %d\n", contactForm.User.ID)
fmt.Fprintf(resp, "Message: %s\n", contactForm.Message)
}
func main() {
http.HandleFunc("/contact", handler)
http.ListenAndServe(":3000", nil)
}
Conform- keep user input in check (go, golang)
Trim, sanitize, and modify struct string fields in place, based on tags.
Now also works with embedded structs
Turns this...
type Person struct {
FirstName string `conform:"name"`
LastName string `conform:"ucfirst,trim"`
Email string `conform:"email"`
CamelCase string `conform:"camel"`
UserName string `conform:"snake"`
Slug string `conform:"slug"`
Blurb string `conform:"title"`
Left string `conform:"ltrim"`
Right string `conform:"rtrim"`
}
p1 := Person{
" LEE ",
" Benson",
" LEE@LEEbenson.com ",
"I love new york city",
"lee benson",
"LeeBensonWasHere",
"this is a little bit about me...",
" Left trim ",
" Right trim ",
}
Into this...
p2 := p1 // <-- copy the Person struct into a new one, to see the difference
conform.Strings(&p2) // <-- this does the work
/*
p1 (left) vs. p2 (right)
FirstName: ' LEE ' -> 'Lee'
LastName: ' Benson' -> 'Benson'
Email: ' LEE@LEEbenson.com ' -> 'lee@leebenson.com'
CamelCase: 'I love new york city' -> 'ILoveNewYorkCity'
UserName: 'lee benson' -> 'lee_benson'
Slug: 'LeeBensonWasHere' -> 'lee-benson-was-here'
Blurb: 'this is a little bit about me...' -> 'This Is A Little Bit About Me...'
Left: ' Left trim ' -> 'Left trim '
Right: ' Right trim ' -> ' Right trim'
*/
Package form Decodes url.Values into Go value(s) and Encodes Go value(s) into url.Values.
Use go get.
go get github.com/go-playground/form
Then import the form package into your own code.
import "github.com/go-playground/form/v4"
.
for separating fields/structs. (eg. structfield.field
)[index or key]
for access to index of a slice/array or key for map. (eg. arrayfield[0]
, mapfield[keyvalue]
)<form method="POST">
<input type="text" name="Name" value="joeybloggs"/>
<input type="text" name="Age" value="3"/>
<input type="text" name="Gender" value="Male"/>
<input type="text" name="Address[0].Name" value="26 Here Blvd."/>
<input type="text" name="Address[0].Phone" value="9(999)999-9999"/>
<input type="text" name="Address[1].Name" value="26 There Blvd."/>
<input type="text" name="Address[1].Phone" value="1(111)111-1111"/>
<input type="text" name="active" value="true"/>
<input type="text" name="MapExample[key]" value="value"/>
<input type="text" name="NestedMap[key][key]" value="value"/>
<input type="text" name="NestedArray[0][0]" value="value"/>
<input type="submit"/>
</form>
Decoding
package main
import (
"fmt"
"log"
"net/url"
"github.com/go-playground/form/v4"
)
// Address contains address information
type Address struct {
Name string
Phone string
}
// User contains user information
type User struct {
Name string
Age uint8
Gender string
Address []Address
Active bool `form:"active"`
MapExample map[string]string
NestedMap map[string]map[string]string
NestedArray [][]string
}
// use a single instance of Decoder, it caches struct info
var decoder *form.Decoder
func main() {
decoder = form.NewDecoder()
// this simulates the results of http.Request's ParseForm() function
values := parseForm()
var user User
// must pass a pointer
err := decoder.Decode(&user, values)
if err != nil {
log.Panic(err)
}
fmt.Printf("%#v\n", user)
}
// this simulates the results of http.Request's ParseForm() function
func parseForm() url.Values {
return url.Values{
"Name": []string{"joeybloggs"},
"Age": []string{"3"},
"Gender": []string{"Male"},
"Address[0].Name": []string{"26 Here Blvd."},
"Address[0].Phone": []string{"9(999)999-9999"},
"Address[1].Name": []string{"26 There Blvd."},
"Address[1].Phone": []string{"1(111)111-1111"},
"active": []string{"true"},
"MapExample[key]": []string{"value"},
"NestedMap[key][key]": []string{"value"},
"NestedArray[0][0]": []string{"value"},
}
}
A Go package to decode HTTP form and query parameters. The only requirement is Go 1.12 or later.
go get github.com/monoculum/formam/v3
maps
, structs
and slices
.UnmarshalText()
interface in values and keys of maps.map
keys are string
, int
and variants, uint
and variants, uintptr
, float32
, float64
, bool
, struct
, custom types
to one of the above types registered by function or UnmarshalText
method, a pointer
to one of the above typesinterface{}
that has a map
, struct
or slice
as value is accessible.time.Time
with format 2006-01-02
by its UnmarshalText()
method.url.URL
.slice
and array
types without explicitly indicating an index.You can see the performance in formam-benchmark compared with ajg/form, gorilla/schema, go-playground/form and built-in/json.
.
to access a struct field (e.g. struct.field1
).[<index>]
to access tje specific slice/array index (e.g. struct.array[0]
). It's not necessary to add an index to append data.[<key>]
to access map keys (e.g.. struct.map[es-ES]
).<form method="POST">
<input type="text" name="Name" value="Sony" />
<input type="text" name="Location.Country" value="Japan" />
<input type="text" name="Location.City" value="Tokyo" />
<input type="text" name="Products[0].Name" value="Playstation 4" />
<input type="text" name="Products[0].Type" value="Video games" />
<input type="text" name="Products[1].Name" value="TV Bravia 32" />
<input type="text" name="Products[1].Type" value="TVs" />
<input type="text" name="Founders[0]" value="Masaru Ibuka" />
<input type="text" name="Founders[0]" value="Akio Morita" />
<input type="text" name="Employees" value="90000" />
<input type="text" name="public" value="true" />
<input type="url" name="website" value="http://www.sony.net" />
<input type="date" name="foundation" value="1946-05-07" />
<input type="text" name="Interface.ID" value="12" />
<input type="text" name="Interface.Name" value="Go Programming Language" />
<input type="submit" />
</form>
Forms is a lightweight, but incredibly useful go library for parsing form data from an http.Request. It supports multipart forms, url-encoded forms, json data, and url query parameters. It also provides helper methods for converting data into other types and a Validator object which can be used to validate the data. Forms is framework-agnostic and works directly with the http package.
Version 0.4.0
Forms is being actively developed and is well-tested. However, since it is still a young library, it is not recommended for use in mission-critical production applications at this time. It is probably fine to use for low-traffic hobby sites, and in fact we encourage its use in those settings to help polish the API and find missing features and hidden bugs. Pull requests and issue reports are much appreciated :)
Forms follows semantic versioning but offers no guarantees of backwards compatibility until version 1.0. Keep in mind that breaking changes might occur. We will do our best to make the community aware of any non-trivial breaking changes beforehand. We recommend using a dependency vendoring tool such as godep to ensure that breaking changes will not break your application.
Install like you would any other package:
go get github.com/albrow/forms
Then include the package in your import statements:
import "github.com/albrow/forms"
Meant to be used inside the body of an http.HandlerFunc or any function that has access to an http.Request.
func CreateUserHandler(res http.ResponseWriter, req *http.Request) {
// Parse request data.
userData, err := forms.Parse(req)
if err != nil {
// Handle err
// ...
}
// Validate
val := userData.Validator()
val.Require("username")
val.LengthRange("username", 4, 16)
val.Require("email")
val.MatchEmail("email")
val.Require("password")
val.MinLength("password", 8)
val.Require("confirmPassword")
val.Equal("password", "confirmPassword")
val.RequireFile("profileImage")
val.AcceptFileExts("profileImage", "jpg", "png", "gif")
if val.HasErrors() {
// Write the errors to the response
// Maybe this means formatting the errors as json
// or re-rendering the form with an error message
// ...
}
// Use data to create a user object
user := &models.User {
Username: userData.Get("username"),
Email: userData.Get("email"),
HashedPassword: hash(userData.Get("password")),
}
// Continue by saving the user to the database and writing
// to the response
// ...
// Get the contents of the profileImage file
imageBytes, err := userData.GetFileBytes("profileImage")
if err != nil {
// Handle err
}
// Now you can either copy the file over to your server using io.Copy,
// upload the file to something like amazon S3, or do whatever you want
// with it.
}
gbind
Encapsulate general parameter parsing and parameter verification logic,
minimize repetitive code in daily development, and solve parameter binding
and verification in a few lines of code
gbind:"http.path"
gbind:"http.query.varname"
gbind:"http.header.varname"
gbind:"http.form.varname"
gbind:"http.cookie.varname"
json:"varname"
gbind:"http.query.varname,default=123"
RegisterBindFunc
function, such as implementing a binding of the form gbind:"simple.key"
validate
tag, which depends on github.com/go-playground/validator implementation, validate="required,lt=100"
RegisterCustomValidation
functiongbind:"http.cookie.Token" validate="required,lt=100" err_msg="Please complete the login"
package gbind
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"net/url"
)
type Params struct {
API string `gbind:"http.path,default=/api/test"`
Appkey string `gbind:"http.query.appkey,default=appkey-default"`
Page int `gbind:"http.query.page,default=1"`
Size int `gbind:"http.query.size,default=10"`
Token string `gbind:"http.cookie.Token" validate:"required" err_msg:"please login"`
Host string `gbind:"http.header.host,default=www.baidu.com"`
Uids []int `gbind:"http.form.uids"`
}
func Controller(w http.ResponseWriter, r *http.Request) {
var requestParams = &Params{}
if _, err := BindWithValidate(context.Background(), requestParams, r); err != nil {
w.WriteHeader(http.StatusBadRequest)
return
}
bs, _ := json.MarshalIndent(requestParams, "", "\t")
w.Write(bs)
}
func ExampleGbind() {
w := httptest.NewRecorder()
u, _ := url.Parse("http://gbind.baidu.com/api/test?appkey=abc&page=2")
r := &http.Request{
Method: http.MethodPost,
Header: map[string][]string{
"Host": {"gbind.baidu.com"},
},
PostForm: url.Values{
"uids": {"1", "2", "3"},
},
URL: u,
}
r.AddCookie(&http.Cookie{
Name: "Token",
Value: "foo-bar-andsoon",
})
Controller(w, r)
fmt.Println(w.Result().Status)
fmt.Println(w.Body.String())
// Output:
// 200 OK
//{
// "API": "/api/test",
// "Appkey": "abc",
// "Page": 2,
// "Size": 10,
// "Token": "foo-bar-andsoon",
// "Host": "gbind.baidu.com",
// "Uids": [
// 1,
// 2,
// 3
// ]
//}
}
gorilla/csrf is a HTTP middleware library that provides cross-site request forgery (CSRF) protection. It includes:
csrf.Protect
middleware/handler provides CSRF protection on routes attached to a router or a sub-router.csrf.Token
function that provides the token to pass into your response, whether that be a HTML form or a JSON response body.csrf.TemplateField
helper that you can pass into your html/template
templates to replace a {{ .csrfField }}
template tag with a hidden input field.gorilla/csrf is designed to work with any Go web framework, including:
http.Handler
interface.gorilla/csrf is also compatible with middleware 'helper' libraries like Alice and Negroni.
With a properly configured Go toolchain:
go get github.com/gorilla/csrf
gorilla/csrf is easy to use: add the middleware to your router with the below:
CSRF := csrf.Protect([]byte("32-byte-long-auth-key"))
http.ListenAndServe(":8000", CSRF(r))
...and then collect the token with csrf.Token(r)
in your handlers before passing it to the template, JSON body or HTTP header (see below).
Note that the authentication key passed to csrf.Protect([]byte(key))
should:
Generating a random key won't allow you to authenticate existing cookies and will break your CSRF validation.
gorilla/csrf inspects the HTTP headers (first) and form body (second) on subsequent POST/PUT/PATCH/DELETE/etc. requests for the token.
Here's the common use-case: HTML forms you want to provide CSRF protection for, in order to protect malicious POST requests being made:
package main
import (
"net/http"
"github.com/gorilla/csrf"
"github.com/gorilla/mux"
)
func main() {
r := mux.NewRouter()
r.HandleFunc("/signup", ShowSignupForm)
// All POST requests without a valid token will return HTTP 403 Forbidden.
// We should also ensure that our mutating (non-idempotent) handler only
// matches on POST requests. We can check that here, at the router level, or
// within the handler itself via r.Method.
r.HandleFunc("/signup/post", SubmitSignupForm).Methods("POST")
// Add the middleware to your router by wrapping it.
http.ListenAndServe(":8000",
csrf.Protect([]byte("32-byte-long-auth-key"))(r))
// PS: Don't forget to pass csrf.Secure(false) if you're developing locally
// over plain HTTP (just don't leave it on in production).
}
func ShowSignupForm(w http.ResponseWriter, r *http.Request) {
// signup_form.tmpl just needs a {{ .csrfField }} template tag for
// csrf.TemplateField to inject the CSRF token into. Easy!
t.ExecuteTemplate(w, "signup_form.tmpl", map[string]interface{}{
csrf.TemplateTag: csrf.TemplateField(r),
})
// We could also retrieve the token directly from csrf.Token(r) and
// set it in the request header - w.Header.Set("X-CSRF-Token", token)
// This is useful if you're sending JSON to clients or a front-end JavaScript
// framework.
}
func SubmitSignupForm(w http.ResponseWriter, r *http.Request) {
// We can trust that requests making it this far have satisfied
// our CSRF protection requirements.
}
Note that the CSRF middleware will (by necessity) consume the request body if the token is passed via POST form values. If you need to consume this in your handler, insert your own middleware earlier in the chain to capture the request body.
httpin helps you easily decoding HTTP request data from
?name=john&is_member=true
Authorization: xxx
username=john&password=******
POST {"name":"john"}
/users/{username}
You only need to define a struct to receive/bind data from an HTTP request, without writing any parsing stuff code by yourself.
type ListUsersInput struct {
Page int `in:"query=page"`
PerPage int `in:"query=per_page"`
IsMember bool `in:"query=is_member"`
}
func ListUsers(rw http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*ListUsersInput)
if input.IsMember {
// Do sth.
}
// Do sth.
}
httpin is:
net/http
packagefunc ListUsers(rw http.ResponseWriter, r *http.Request) {
page, err := strconv.ParseInt(r.FormValue("page"), 10, 64)
if err != nil {
// Invalid parameter: page.
return
}
perPage, err := strconv.ParseInt(r.FormValue("per_page"), 10, 64)
if err != nil {
// Invalid parameter: per_page.
return
}
isMember, err := strconv.ParseBool(r.FormValue("is_member"))
if err != nil {
// Invalid parameter: is_member.
return
}
// Do sth.
}
nosurf
is an HTTP package for Go that helps you prevent Cross-Site Request Forgery attacks. It acts like a middleware and therefore is compatible with basically any Go HTTP application.
Even though CSRF is a prominent vulnerability, Go's web-related package infrastructure mostly consists of micro-frameworks that neither do implement CSRF checks, nor should they.
nosurf
solves this problem by providing a CSRFHandler
that wraps your http.Handler
and checks for CSRF attacks on every non-safe (non-GET/HEAD/OPTIONS/TRACE) method.
nosurf
requires Go 1.1 or later.
http.Handler
(frameworks, your own handlers, etc.) and acts like one itself.HTTP 400
? No problem.package main
import (
"fmt"
"github.com/justinas/nosurf"
"html/template"
"net/http"
)
var templateString string = `
<!doctype html>
<html>
<body>
{{ if .name }}
<p>Your name: {{ .name }}</p>
{{ end }}
<form action="/" method="POST">
<input type="text" name="name">
<!-- Try removing this or changing its value
and see what happens -->
<input type="hidden" name="csrf_token" value="{{ .token }}">
<input type="submit" value="Send">
</form>
</body>
</html>
`
var templ = template.Must(template.New("t1").Parse(templateString))
func myFunc(w http.ResponseWriter, r *http.Request) {
context := make(map[string]string)
context["token"] = nosurf.Token(r)
if r.Method == "POST" {
context["name"] = r.FormValue("name")
}
templ.Execute(w, context)
}
func main() {
myHandler := http.HandlerFunc(myFunc)
fmt.Println("Listening on http://127.0.0.1:8000/")
http.ListenAndServe(":8000", nosurf.New(myHandler))
}
Thank you for following this article.