Golang Serve Fundamentals and Advanced Topics

Author

Reads 926

Various tangled wires connected to system near black metal cases in server room
Credit: pexels.com, Various tangled wires connected to system near black metal cases in server room

Golang's built-in http package is the foundation of the Serve function, which is responsible for handling HTTP requests and serving HTTP responses.

The Serve function listens on a specific address and port, allowing it to receive incoming requests from clients.

By default, the Serve function serves files from the current working directory, but it can be configured to serve files from a different directory using the ServeFile function.

This allows developers to serve static files, such as images or CSS files, from a specific directory.

The Serve function also supports serving HTTP responses with a specific status code, such as 404 for a not found error.

This is particularly useful when handling errors or exceptions in a web application.

The Serve function can also be used to serve HTTPS responses by passing a TLS configuration to the ListenAndServe function.

This requires a TLS certificate and private key to be set up in the application.

The Serve function is a fundamental component of any web application built with Golang, and understanding its basics is crucial for building robust and scalable web services.

Basic Server Setup

Credit: youtube.com, DIY Golang Web Server: No Dependencies Needed!

To set up a basic server in Go, you'll want to start with a simple file server that serves files from the local filesystem. This is ridiculously simple to write in Go, and can be done with just a few lines of code.

A basic static server can be created with the following code: it serves the files directory at the root route of the server (/). If you run this server and open the browser to localhost:9999, you'll see the directory listing.

Here are the key features of a basic server setup:

  • Serves files from the local filesystem
  • Serves a simple listing of directory contents when requested
  • Serves files with the correct HTTP MIME type based on the file's contents

Hello World Server

Creating a Hello World server is a great way to get started with setting up a basic server. A simple static server that serves files from the local filesystem is ridiculously simple to write in Go.

This server serves the files directory at the root route of the server (/). If we run this server and open the browser to localhost:9999, we'll see the directory's contents.

A unique perspective: Simple Http Server Golang Github

Credit: youtube.com, Creating a Simple Hello World HTTP Server in Go

To create a more interactive server, we can use a http.Handler, which implements ServeHTTP. This allows us to respond to specific endpoints, like the /hello endpoint.

A http.Handler can be useful for adding middleware components, such as authentication, tracing, and recording request duration.

We can also use http.Handle to map the /hello endpoint to the type that handles it. This is cleaner and more maintainable than using a http.Handler.

Alternatively, we can use http.HandleFunc, which makes it even simpler to set up a Hello World server. We can rename the ServeHTTP method to match the expected function signature.

Consider reading: Hello World Golang

Wait Groups

Using Wait Groups in Your Server Setup is a good practice to ensure your servers run smoothly and exit cleanly. This approach is especially useful when dealing with multiple servers.

By placing servers in their own goroutines, you can have the main goroutine wait until they shutdown before shutting the whole service down. This makes the code more explicit and clear about what's happening.

Credit: youtube.com, Wait groups in golang

You can use Wait Groups to achieve this, as shown in the example where both servers run and can be cURLed. However, be aware that the log line after wg.Wait() might be missing, which can lead to debugging issues.

The issue is that ListenAndServe might be calling os.Exit(1) somewhere, resulting in an exit code 1 when the server shuts down. This can be a problem if you're trying to add cleanup code just before the service shuts down.

Recommended read: Golang Source

Serving Static Content

Serving static content is a crucial part of building a web application, and Go makes it surprisingly easy. You can serve files on a different route than the root route by using the `StripPrefix` function.

To serve static content, you can use the `http.FileServer` function and point it to a URL path. This is useful for serving files like JavaScript, CSS, and images. The `http.FileServer` function needs to know where to serve files from, so you need to strip away a part of the URL path.

A fresh viewpoint: Golang Url

Credit: youtube.com, Serving Static Files in Go & Example with NextJS (Ep. 5) | Backend with Golang from Scratch Series

You can use the `StripPrefix` function to remove the actual directory prefix from requests made to the file server. For example, if you want to serve files in the `static` directory, you can use `StripPrefix` to remove the `static` prefix from requests.

Here's a simple example of how to serve static content:

  • Serve files from the `files` directory in the `static` route.
  • Use `StripPrefix` to remove the `static` prefix from requests.

By using `http.FileServer` and `StripPrefix`, you can easily serve static content in your Go web application. This is a great way to get started with serving static assets like JavaScript, CSS, and images.

Customizing the Server

We can create a custom HTTP server in Go by creating a new `http.Server` in the main function. This allows us to set additional arguments that can be used in production.

The default `http` server created with `http.ListenAndServe` is probably sufficient for side projects, but it's not ideal for production. By creating a custom server, we can have more control over its configuration.

Here are some of the arguments that can be set in the `http.Server` type: ServeMux: This is the default ServeMux, which we'll learn more about in the next section.Addr: The address on which the server will listen.Handler: The handler function that will handle incoming requests.WriteTimeout: The maximum amount of time the server will wait for a write operation to complete.ReadTimeout: The maximum amount of time the server will wait for a read operation to complete.

Curious to learn more? Check out: Golang Set Env Variable

Custom Server

People Using Computers at Work
Credit: pexels.com, People Using Computers at Work

You can create a custom http server by creating a new http.Server in the main function. This is useful for productionizing your server.

The default http server created by http.ListenAndServe is probably good enough for side projects, but it may not be suitable for production use.

To create a custom server, you can specify additional arguments in the http.Server type. Take a look in the documentation for more information.

Here are some key arguments you can set in the http.Server type:

By creating a custom server, you can customize its behavior to suit your needs.

Create Admin Server

To create an admin server, you can simply declare a new ServeMux and Server instance, just like you did for the hello server. This will allow you to serve admin-specific endpoints on a different port.

You can change the port to 8081, as done in Example 4, to avoid conflicts with the hello server. This is especially useful when you want to expose admin endpoints over the public internet while keeping the hello server private.

Woman using a laptop in a server room, showcasing modern technology and work environment.
Credit: pexels.com, Woman using a laptop in a server room, showcasing modern technology and work environment.

To add a new endpoint, simply use the ServeMux's HandleFunc method, as shown in Example 4. In this case, a new endpoint /ping was added with a simple liveness check that responds with "pong".

Depending on the order the servers are declared in the main function, you might only be able to get a response from one server, as noted in Example 4. To avoid this, make sure to declare the admin server last.

Using a custom ServeMux, as shown in Example 5, can help keep the admin endpoint code separate from the hello endpoint code. This will prevent accidental mixing of the two.

Handling HTTP Requests

Handling HTTP requests in Go is a straightforward process. The http package provides a simple and efficient way to handle requests, making it a great choice for web development.

The http package operates by creating a listening socket, listening to a port, and waiting for clients. Once a client request is received, the package accepts the request, creates a new connection, and starts a new goroutine to handle the request.

Credit: youtube.com, THIS is the BEST Way to Write HTTP Services in Golang

To handle requests, Go uses the Serve function, which is called on the server object. This function accepts a request, parses the HTTP header, and passes the request data to the handler. The handler is responsible for processing the request and returning a response.

Here's a high-level overview of the request handling process:

  1. Create a listening socket and listen to a port.
  2. Accept client requests and create a new connection.
  3. Start a new goroutine to handle the request and pass the request data to the handler.

The handler is typically a function that processes the request and returns a response. In Go, handlers can be registered using the HandleFunc function, which maps a URL pattern to a handler function. This makes it easy to create web applications with multiple routes and handlers.

Hello World with Http.HandleFunc

The "Hello World with http.HandleFunc" approach is a great way to simplify your HTTP request handling. This method allows you to handle requests without having to create a type that implements ServeHTTP. You can rename the ServeHTTP method to hello to clarify which endpoint it handles.

The hello function needs to match the expected function signature required by http.HandleFunc, which is the same as ServeHTTP. This is a more straightforward approach than creating a custom handler type.

Credit: youtube.com, What are HTTP requests?

The key benefit of this approach is that it's simpler and more maintainable than the other methods. You can easily add or remove handlers without having to modify the underlying code.

Here's a simple example of how to use http.HandleFunc:

```go

http.HandleFunc("/", sayhelloName)

```

This line of code registers the router rule for the "/" path, which will call the sayhelloName function when the URL is accessed.

The Middleware Pattern

The Middleware Pattern is a useful way to extend the functionality of something without changing the existing implementation. This aligns with the SOLID principles, specifically the Open Closed Principle.

It's a pattern where we can separate concerns and make our code more maintainable. We can simulate a scenario where we're retrieving user details and recording the request duration.

The DefaultServeMux is a built-in ServeMux in Go that handles endpoint mapping. We can use it by passing it to the ListenAndServe function.

Middleware doesn't care about what's happening next, it's just concerned with its own job. This is a good example of decoupling.

By passing DefaultServeMux to middleware, we can chain multiple middleware components together. Each middleware component implements the http.Handler interface.

This allows us to extend the functionality of our HTTP requests without modifying the existing implementation. It's a powerful pattern that makes our code more flexible and maintainable.

Signals

Credit: youtube.com, Http client interceptors signals live broadcast

When working with HTTP requests, it's essential to have control over the shutdown process to log messages before the service shuts down. We can use the signal package to achieve this.

The signal package helps us orchestrate the shutdown with the use of a sigterm signal and the context. This allows us to register the sigint signal onto a new channel of type os.Signal.

By registering the sigint signal, we can action on any cleanup code and logging before gracefully shutting down the service. This gives us control over the shutdown process.

We can also use context.WithCancel to force the shutdown of servers, preventing them from waiting indefinitely for live connections to close. This is especially useful when dealing with servers that may have open connections.

Context.WithCancel allows us to force the shutdown, giving us more control over the process. This is particularly important when we need to ensure that the service shuts down cleanly and efficiently.

Server Configuration and Management

Credit: youtube.com, Golang Web Server Tutorial - Step #6 - Serve File

Serving a complete web application in Go involves both a server component and a client component. The client component is made up of HTML, CSS, and JavaScript files served from the server's filesystem and interpreted by the user's browser.

The server component is any number of functions responding to specific HTTP routes for the JS in the client to communicate with. We can serve a complete web application from Go using the foundations established in the previous example.

The server component is in server.go, while the client component is in the public directory, which is visible to users in their browser via "View page source" or dev tools. This is because the public directory is called "public" for this reason.

Serving the client side of the application from the file system in the root route / is one key functionality. We can also serve a dynamic server function providing the current time on the /time route.

Credit: youtube.com, Build a web server with go

If we run the server locally and open a browser to localhost:9999, we'll see a clock "ticking" by updating its time every second. This is a result of the dynamic server function updating the time every second.

Creating a custom http server is also possible in Go. We can create a new http.Server in the main function using the http.ListenAndServe function, but this might not be suitable for production use.

A custom http server can be created by setting additional arguments in the http.Server type. We can look up the available arguments in the documentation for more information.

Here's a list of key server configurations:

  • Serves the client side of the application from the file system in the root route /.
  • Serves a dynamic server function providing the current time on the /time route.
  • Can be configured with additional arguments in the http.Server type.

Advanced Server Topics

For more complex projects, a custom HTTP server is often necessary. We can create a custom HTTP server by creating a new `http.Server` in the main function.

The default `http.ListenAndServe` server is probably good enough for side projects, but it's not suitable for production.

To create a custom server, we need to look into the `http.Server` type documentation. There are many more arguments that can be set.

A default `ServeMux` is still used in a custom server, but we'll create our own in the next section.

Francis McKenzie

Writer

Francis McKenzie is a skilled writer with a passion for crafting informative and engaging content. With a focus on technology and software development, Francis has established herself as a knowledgeable and authoritative voice in the field of Next.js development.

Love What You Read? Stay Updated!

Join our community for insights, tips, and more.