Generating and managing a DOI in Go

A DOI (Digital Object Identifier) is a standard used to uniquely identify digital content such as scientific articles, datasets, and publications. In this article, we’ll see how to generate and manage a DOI in Go, simulating interaction with registration APIs (such as those from Crossref or DataCite).

1. What is a DOI

A DOI is an alphanumeric string, usually composed of a prefix and a suffix separated by a slash. For example: 10.1234/abcde.2025.001. DOIs are generally registered through certified agencies that provide APIs for creation, updating, and resolution.

2. Generating a DOI

You can generate a DOI locally by creating a string that follows the correct syntax. Here’s a simple example in Go:


package main

import (
    "crypto/rand"
    "fmt"
)

func generateDOI(prefix string) string {
    suffix := make([]byte, 6)
    rand.Read(suffix)
    for i := range suffix {
        suffix[i] = "abcdefghijklmnopqrstuvwxyz0123456789"[suffix[i]%36]
    }
    return fmt.Sprintf("%s/%s", prefix, string(suffix))
}

func main() {
    doi := generateDOI("10.1234")
    fmt.Println("Generated DOI:", doi)
}

3. Registration via API

After generating a DOI, you need to register it with an organization like DataCite. Here’s an example HTTP POST request to register a DOI:


package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

type Metadata struct {
    Data struct {
        Type       string `json:"type"`
        Attributes struct {
            DOI   string `json:"doi"`
            Title string `json:"titles"`
            // Other metadata
        } `json:"attributes"`
    } `json:"data"`
}

func registerDOI(doi, title string) error {
    metadata := Metadata{}
    metadata.Data.Type = "dois"
    metadata.Data.Attributes.DOI = doi
    metadata.Data.Attributes.Title = title

    payload, _ := json.Marshal(metadata)
    req, _ := http.NewRequest("POST", "https://api.test.datacite.org/dois", bytes.NewBuffer(payload))
    req.Header.Set("Content-Type", "application/vnd.api+json")
    req.SetBasicAuth("USERNAME", "PASSWORD")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    if resp.StatusCode != http.StatusCreated {
        return fmt.Errorf("Registration error: %s", resp.Status)
    }
    return nil
}

4. Updating and managing

To update a registered DOI, you can send an HTTP PUT request to the same endpoint:


// Similar to the previous function but using PUT method
req, _ := http.NewRequest("PUT", "https://api.test.datacite.org/dois/10.1234/xyz123", bytes.NewBuffer(payload))

5. Resolving a DOI

DOIs can be resolved with a simple redirect using https://doi.org/. For example:


package main

import (
    "fmt"
    "net/http"
)

func resolveDOI(doi string) error {
    url := fmt.Sprintf("https://doi.org/%s", doi)
    resp, err := http.Get(url)
    if err != nil {
        return err
    }
    defer resp.Body.Close()

    fmt.Println("Redirected to:", resp.Request.URL)
    return nil
}

Conclusion

Generating and managing a DOI in Go is relatively straightforward but requires attention when building metadata and interacting with official APIs. For production use, it’s essential to handle authentication securely and comply with the registering agency’s specifications.

Back to top