Skip to content

Commit

Permalink
Add joke api exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
LorenzBischof committed Oct 25, 2023
1 parent 3cc17e0 commit cad2c1c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
42 changes: 42 additions & 0 deletions content/en/docs/exercises/lab_joke_api/_index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
title: "Joke API"
weight: 9151
---

Try and solve the following. Every task has links to relevant documentation.

### Request an API
1. Begin with the following [main.go](main.txt) which requests a joke from https://official-joke-api.appspot.com/random_joke and decodes it into a Go struct.
2. Refactor the HTTP request into another [function](/docs/basics/functions/) that returns `joke, error`
3. Update the code to also [decode](/docs/standard-library/json/) and print the punchline
4. [Delay](https://pkg.go.dev/time#Sleep) the punchline by a few seconds
5. Make the delay configurable with a `--delay 10` [flag](https://pkg.go.dev/flag)

### Build an API
6. Write another program that [reads](https://pkg.go.dev/os#ReadFile) a [json file](https://github.com/15Dkatz/official_joke_api/blob/master/jokes/index.json) and picks a [random](https://pkg.go.dev/math/rand#Intn) joke
7. Implement a [HTTP Server](/docs/standard-library/http-server/) that serves the picked joke
8. Add a new endpoint that expects a joke and [persists](/docs/standard-library/io/) it

### Use an API
9. Write another program that asks the user to enter a joke on the command line (standard input) and [sends](/docs/standard-library/http-client/) it to your own API.


## Tips

{{%details title="Project structure"%}}
You cannot have multiple `main` functions in a single directory. If you want to create multiple binaries, these must be separated into different directories. By convention the directory equals the binary name and is located under `cmd/` (e.g. `cmd/request-joke/main.go`).
{{%/details%}}

{{%details title="Prompt for input on the command line (standard input)"%}}
With the [bufio](https://pkg.go.dev/bufio) package we can read from the standard input ([os.Stdin](https://pkg.go.dev/os#Stdin)) until a certain character occurs:

```golang
line, err := bufio.NewReader(os.Stdin).ReadString('\n')
```

The [strings](https://pkg.go.dev/strings) package contains various functions to work with strings. For example [strings.TrimSpace](https://pkg.go.dev/strings#TrimSpace) to remove whithspace characters (spaces, newlines, etc.) from strings.

```golang
line = strings.TrimSpace(line)
```
{{%/details%}}
61 changes: 61 additions & 0 deletions content/en/docs/exercises/lab_joke_api/main.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// If you want to create an executable binary,
// you must name your package `main`.
// By using another name, you create a library.
package main

// Import external modules that you would like to use
import (
"encoding/json" // JSON encoding and decoding
"fmt" // Formatting
"io" // Input/Output
"net/http" // HTTP requests
"os" // Operating System
)

type joke struct {
Type string
// The json key can be overridden
Message string `json:"setup"`
}

// The main function is called when executing the binary
func main() {
// Variables are declared using `:=`
// The type is automatically evaluated and cannot be modified
url := "https://official-joke-api.appspot.com/random_joke"
// The following will not work:
// url = 9

// Output a string to the terminal
// %v detects the variable type. You may also use %s for strings and %d for digits
fmt.Printf("Requesting joke from %v\n", url)
// The following would also work:
// fmt.Println("Requesting joke from", url)

// Functions can return multiple results!
// The variable names can be freely modified,
// but using `err` for the error result is a convention.
res, err := http.Get(url)
// If the error is not nil, it means an error has occurred
if err != nil {
fmt.Printf("Error making http request: %v\n", err)
// Exit the program with statuscode 1
os.Exit(1)
}
body, err := io.ReadAll(res.Body)
if err != nil {
fmt.Printf("Error reading response body: %v\n", err)
os.Exit(1)
}
fmt.Printf("Body: %s\n", body)

// Initialize a new instance of the joke struct
j := joke{}
// Pass a pointer of j to json.Unmarshal
err = json.Unmarshal(body, &j)
if err != nil {
fmt.Printf("Error decoding body: %v\n", err)
os.Exit(1)
}
fmt.Printf("%+v", j)
}

0 comments on commit cad2c1c

Please sign in to comment.