Skip to content
This repository was archived by the owner on Jan 9, 2026. It is now read-only.

Latest commit

 

History

History

README.md

An HTTP Server

In this part, you will implement an HTTP server as a frontend to your application. Review the documentation on listeners. First, update your struct that implements the Main component to include a weaver.Listener called "emojis". We recommend you print out the listener to show the address the listener is listening on.

Solution.

workshops/04/main.go

Lines 36 to 45 in 4eca79e

// app is the main component of our application.
type app struct {
weaver.Implements[weaver.Main]
searcher weaver.Ref[Searcher]
lis weaver.Listener `weaver:"emojis"`
}
// run implements the application main.
func run(ctx context.Context, a *app) error {
a.Logger(ctx).Info("emojis listener available.", "addr", a.lis)

Next, inside of the function you pass to weaver.Run, implement an HTTP handler for the /search endpoint. The endpoint receives GET requests of the form /search?q=<query> and returns the JSON serialized list of emojis that match the query (json.Marshal). For example, curl "localhost:9000/search?q=pig" should return ["🐖","🐗","🐷","🐽"]. At the end of the function, call http.Serve to serve HTTP traffic using the handler you just implemented.

Solution.

workshops/04/main.go

Lines 43 to 78 in 4eca79e

// run implements the application main.
func run(ctx context.Context, a *app) error {
a.Logger(ctx).Info("emojis listener available.", "addr", a.lis)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
if _, err := fmt.Fprint(w, indexHtml); err != nil {
a.Logger(r.Context()).Error("error writing index.html", "err", err)
}
})
http.HandleFunc("/search", func(w http.ResponseWriter, r *http.Request) {
// Search for the list of matching emojis.
query := r.URL.Query().Get("q")
emojis, err := a.searcher.Get().Search(r.Context(), query)
if err != nil {
a.Logger(r.Context()).Error("error getting search results", "err", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// JSON serialize the results.
bytes, err := json.Marshal(emojis)
if err != nil {
a.Logger(r.Context()).Error("error marshaling search results", "err", err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if _, err := fmt.Fprintln(w, string(bytes)); err != nil {
a.Logger(r.Context()).Error("error writing search results", "err", err)
}
})
return http.Serve(a.lis, nil)
}

Next, create a config file called config.toml with the following contents to configure the address of the listener.

[single]
listeners.emojis = {address = "localhost:9000"}

Finally, run your application. You can provide the config file using the SERVICEWEAVER_CONFIG environment variable. Your application should block serving traffic.

$ weaver generate .
$ SERVICEWEAVER_CONFIG=config.toml go run .

In a separate terminal, curl the /search endpoint:

$ curl "localhost:9000/search?q=pig"
["🐖","🐗","🐷","🐽"]
$ curl "localhost:9000/search?q=cow"
["🐄","🐮"]
$ curl "localhost:9000/search?q=baby%20bird"
["🐣","🐤","🐥"]

If you do not have curl installed on your machine or if your terminal does not render emojis well, you can instead use a web browser. If you visit localhost:9000/search?q=pig, for example, you should see a page with ["🐖","🐗","🐷","🐽"] as its contents.

While your application is running, run weaver single status to see information about the application.

$ weaver single status
╭─────────────────────────────────────────────────────╮
│ DEPLOYMENTS                                         │
├────────┬──────────────────────────────────────┬─────┤
│ APP    │ DEPLOYMENT                           │ AGE │
├────────┼──────────────────────────────────────┼─────┤
│ emojis │ 370e6a90-22ba-4b1f-8558-86d90b516a54 │ 9s  │
╰────────┴──────────────────────────────────────┴─────╯
╭──────────────────────────────────────────────────────╮
│ COMPONENTS                                           │
├────────┬────────────┬─────────────────┬──────────────┤
│ APP    │ DEPLOYMENT │ COMPONENT       │ REPLICA PIDS │
├────────┼────────────┼─────────────────┼──────────────┤
│ emojis │ 370e6a90   │ emojis.Searcher │ 3493842      │
│ emojis │ 370e6a90   │ main            │ 3493842      │
╰────────┴────────────┴─────────────────┴──────────────╯
╭──────────────────────────────────────────────────╮
│ LISTENERS                                        │
├────────┬────────────┬──────────┬─────────────────┤
│ APP    │ DEPLOYMENT │ LISTENER │ ADDRESS         │
├────────┼────────────┼──────────┼─────────────────┤
│ emojis │ 370e6a90   │ emojis   │ 127.0.0.1:12347 │
╰────────┴────────────┴──────────┴─────────────────╯

When you go run . a Service Weaver application, every component is co-located in the same OS process. We can infer this from the output of weaver single status because the two components, main and emojis.Searcher, have the same process id.

(Optional) Web UI

We have written a web UI, index.html, for your app. You can optionally serve index.html on the root endpoint / of your HTTP server. First, import the embed package into main.go.

import _ "embed"

Next, download or copy-and-paste the index.html file into your emojis/ directory. Next, embed the contents of index.html into a package-scoped indexHtml variable in main.go.

//go:embed index.html
var indexHtml string

Finally, register the following HTTP handler.

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
	if r.URL.Path != "/" {
		http.NotFound(w, r)
		return
	}
	fmt.Fprint(w, indexHtml)
})

Re-run your application and open localhost:9000 in a browser. You should see the following web UI.

emoji_search_demo.webm

⬅️ Previous Part     ⚫     Next Part ➡️