Kontakt

Wie schreibt man das in golang?

by Christoph Dähne on 23.02.2021

Ein Hello-World-Beispiel ist super, um ein Projekt anzufangen. Ist meine Entwicklungsumgebung eingerichtet und kann ich das Programm starten? "Hello World!", und es kann losgehen.

Bei der Webentwicklung kann ich allerdings erst so richtig anfangen, wenn mein Programmgerüst HTTP spricht und ich irgendwas speichern und laden kann. Aus diesen Gerüsten entsteht gerade eine kleine Blog-Artikel-Reihe mit Beispielen in verschiedenen Sprachen.

Dieser Blog-Artikel ist Teil einer wachsenden Reihe:

Hier geht es um golang

Disclaimer

Die Beispiele sind minimal gehalten und lassen sich so produktiv nicht einsetzen. Insbesondere das Speichern des Zugriff-Counters in einer Datei ist nur ein Platzhalter. Der Beispiel-Code funktioniert nicht bei parallelen Zugriffen. Trotzdem bin ich der Meinung, dass die Lösung als Beispiel ausreicht. Bitte verstehe die Dateizugriffe als Platzhalter für zBsp Zugriffe auf eine Datenbank.

Die Beispiele kannst du statt dessen gerne als Kopiervorlage benutzen, wie ein Hello-World-Beispiel auch.

Wie schreibt man das in golang?

Hier kommt der golang Code. Das kleine Beispiel passt gerade noch in eine Datei. Wie immer sind Quellcode und Kommentare in Englisch.

// filename: incrementAndGet.go
package main
 
import (
  "log"
  "fmt"
  "io/ioutil"
  "net/http"
  "strconv"
)
 
const dataPath = "data"
const counterPath = dataPath + "/counter.txt"
 
/*
 * Only execute onSuccess unless there is an error err
 */
func onErrorPropagate(
  err error,
  onSuccess func() (int, error)) (int, error) {
  if err != nil {
    return 0, err
  } else {
    return onSuccess()
  }
}
 
/*
 * Read and parse the current counter-file
 */
func loadCounter() (int, error) {
  txt, err := ioutil.ReadFile(counterPath)
  return onErrorPropagate(err, func() (int, error) {
    counter, err := strconv.Atoi(string(txt))
    return onErrorPropagate(err, func() (int, error) {
      return counter, nil
    })
  })
}
 
/*
 * Store the given value as text in the counter-file
 */
func storeCounter(value int) error {
  return ioutil.WriteFile(
    counterPath,
    []byte(
      fmt.Sprintf("%d", value)),
    0644)
}
 
/*
 * Response with "Intenral Server Error (500)" if there is an error,
 * otherwise execute onSuccess.
 */
func onErr500(
  err error,
  w http.ResponseWriter,
  onSuccess func()) {
  if err != nil {
    http.Error(w, err.Error(), 500)
  } else {
    onSuccess()
  }
}
 
/*
 * Entry-point for GET requests to /increment-and-get
 */
func incrementAndGetHandler(
  w http.ResponseWriter,
  r *http.Request) {
  counter, err := loadCounter()
  onErr500(err, w, func() {
    nextCounter := counter + 1
    err := storeCounter(nextCounter)
    onErr500(err, w, func() {
      fmt.Fprintf(w, "value=%d", nextCounter)
    })
  })
}
 
/*
 * Program execution starts here
 */
func main() {
  http.HandleFunc(
    "/increment-and-get",
    incrementAndGetHandler)
  fmt.Println(
    "Please go to http://localhost:8080/increment-and-get")
  log.Fatal(http.ListenAndServe(
    ":8080",
    nil))
}

Sobald deine golang Entwicklungsumgebung installiert ist, kannst du dieses Programm mit dem folgenden Script starten.

#!/usr/bin/env bash
 
set -eux
 
# setup data-directory unless present
if [ ! -d "data" ]; then
  echo "setting up data-directory"
  mkdir data
  echo -n 0 > data/counter.txt
fi
 
go run incrementAndGet.go

Vielen Dank für's Lesen. Wenn du golang lernen willst, schaue dir doch das interaktive Tutorial auf golang.org an. Kontaktiere uns gerne, wenn du Fragen oder Feedback hast.