mist

package module
v0.0.10 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 14, 2024 License: MIT Imports: 18 Imported by: 0

README

mist

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Context

type Context struct {
	Request        *http.Request       // The HTTP request object
	ResponseWriter http.ResponseWriter // The writer to send HTTP responses
	PathParams     map[string]string   // URL path parameters

	MatchedRoute   string // The matched route pattern
	RespData       []byte // Response data to be written to the client
	RespStatusCode int    // HTTP response status code

	UserValues map[string]any // Additional user-defined values to pass through the context
	// contains filtered or unexported fields
}

Context holds all the essential information required for processing an HTTP request. It contains the actual HTTP request, a writer to send the response, path parameters extracted from the URL, query parameters, the route that matched the request, the response data and status code to return to the client, a template engine for rendering views, and a general-purpose map to hold any user-defined values.

func (*Context) BindJSON

func (c *Context) BindJSON(val any) error

BindJSON deserializes the JSON-encoded request body into the provided value. It is often used in the context of HTTP handlers to parse incoming JSON data into a Go data structure.

Parameters:

  • 'val' is a pointer to any Go data structure into which the JSON body of the request will be decoded. This argument must be a non-nil pointer that points to an allocatable or allocated value so that the JSON package can populate the fields of the structure. It must not be nil, as passing nil does not provide a storage location for the decoded data.

The function execution involves the following steps:

  1. It checks if 'val' is nil. If it is, no storage is allocated for the JSON data to be decoded into, so it returns an error using 'errs.ErrInputNil()', indicating that the input value cannot be nil.
  2. It checks if 'c.Request.Body' is nil. If the body is nil, there is no data to decode, and it returns an error using 'errs.ErrBodyNil()', signaling that there is no request body to parse.
  3. It creates a new JSON decoder for the request body and performs the decoding operation using 'decoder.Decode(val)'. If the JSON data in the request body is not well-formed or does not match the expected structure of 'val', json.Decoder will return a relevant error to inform the call site about the issue.

Return Value: - If the decoding is successful, it returns 'nil', indicating that the JSON data has been successfully bound to 'val'. - If an error occurs during decoding, it returns the error, indicating an issue with input validation or the decoding process.

Usage:

  • This method is useful when you want to automatically handle the parsing of JSON data into a Go data structure from an HTTP request. It abstracts away the low-level streaming and decoding of JSON.

Example: - To bind the JSON body of an HTTP request to a struct:

type UserInput struct {
   Name  string `json:"name"`
   Email string `json:"email"`
}

var userInput
if err := c.BindJSON(&userInput); err != nil {
   // handle the error (e.g., send an HTTP 400 Bad Request response)
}

Note:

  • The 'BindJSON' method should be called before accessing the request body by any other means, as the body is an io.ReadCloser and can generally only be read once. Reading the body elsewhere before calling 'BindJSON' will likely result in an EOF error.

func (*Context) BindJSONOpt

func (c *Context) BindJSONOpt(val any, useNumber bool, disableUnknown bool) error

BindJSONOpt deserializes the JSON-encoded request body into the provided value with options to use JSON numbers and disallow unknown fields. This function extends the BindJSON method by providing additional decoding options that can be enabled as needed.

Parameters:

  • 'val' is a pointer to any Go data structure into which the JSON body of the request will be decoded. It must be a non-nil pointer, so it can be populated with decoded data. Passing a nil pointer will result in an error since there would be no allocated structure to decode the data into.
  • 'useNumber' is a boolean option that, when set to true, tells the decoder to decode numbers into an interface{} as a json.Number instead of as a float64. This is useful when precision for large integers is necessary or when the numeric values need to be unmarshalled into a specific typed variable later.
  • 'disableUnknown' is a boolean option that, when set to true, causes the decoder to return an error if it encounters any unknown fields in the JSON data that do not match any fields in the target Go data structure. This can be useful for strict input validation.

The function performs the following steps:

  1. It verifies that 'val' is not nil. If it is nil, it returns an error signaling that a valid pointer is required.
  2. It checks if 'c.Request.Body' is nil, which would indicate that there is no data to decode, and returns an error if this is the case.
  3. It initializes a JSON decoder for the request body. The decoder then checks the 'useNumber' and 'disableUnknown' options to configure its behavior accordingly: a. If 'useNumber' is true, it configures the decoder to treat numbers as json.Number types instead of defaulting them to float64. b. If 'disableUnknown' is true, it configures the decoder to reject unknown fields.
  4. It attempts to decode the JSON request body into 'val'. If the decoding is unsuccessful (for example, due to JSON syntax errors, mismatch between the JSON data and 'val' structure, etc.), it returns the error resulting from the decoder.

Return Value: - Returns 'nil' if the JSON request body has been successfully decoded into 'val'. - Returns an error if 'val' is nil, if there is no request body, or if the JSON decoding process encounters an error.

Usage: - This method is useful for controlling the JSON decoding process in HTTP handlers where there may be a need for more strict or lenient JSON parsing.

Example: - To bind a JSON body to a struct with strict type preservation and unknown field rejection:

type UserInput struct {
   Name string `json:"name"`
   Age  json.Number `json:"age"`
}

var userInput
err := c.BindJSONOpt(&userInput, true, true)
if err != nil {
   // handle the error (e.g., send an HTTP 400 Bad Request response)
}

Note:

  • Similar to BindJSON, BindJSONOpt should be called before any other form of accessing the request body is performed, as it is an io.ReadCloser that allows for a single read operation. This means that calling BindJSONOpt after the body has been read will likely result in an EOF error.

func (*Context) FormValue

func (c *Context) FormValue(key string) StringValue

FormValue extracts a value from the form data in an HTTP request based on the given key. It parses the URL-encoded form data (both in the URL query string and the request body) and retrieves the value associated with the provided key.

Parameters: - 'key' is a string representing the name of the form value to be retrieved from the HTTP request.

The function performs the following actions:

  1. It calls 'c.Request.ParseForm()' to parse the request body as a URL-encoded form. This is necessary to populate 'c.Request.Form' with the form data. This method also parses the query parameters from the URL, merging them into the form values. If parsing fails (for example, if the body can't be read, is too large, or if the content type is not application/x-www-form-urlencoded), an error is returned.
  2. If 'ParseForm()' returns an error, the function creates a 'StringValue' instance with an empty string for 'val' and the parsing error for 'err'. It then returns this 'StringValue' containing the error information.
  3. If 'ParseForm()' succeeds, 'c.Request.FormValue(key)' is used to retrieve the first value for the specified key from the merged form data. A 'StringValue' instance is then returned with the retrieved value and 'nil' for the error.

Return Value:

  • A 'StringValue' instance is always returned. This struct contains two fields: a. 'val' which is the string value retrieved from the form data. b. 'err' which captures any error that may have occurred during the parsing of the form data.

Usage: - This method is intended to be used in HTTP handlers when you need to access form values sent in an HTTP request.

Example: - To retrieve a form value named "email" from an HTTP request:

email := c.FormValue("email")
if email.err != nil {
   // handle the error (e.g., send an HTTP 400 Bad Request response)
}
// Use email.val as the required string value for "email".

Note:

  • The 'FormValue' method does not handle multiple values for the same key. It only retrieves the first such value.
  • Calling 'FormValue' multiple times on the same request is safe as it does not reparse the form data. The form data is parsed only once, and subsequent calls will retrieve values from the already parsed form.
  • The 'ParseForm' method can only parse the request body if the method is "POST" or "PUT" and the content type is "application/x-www-form-urlencoded". For other HTTP methods or content types, the body will not be parsed, but URL query parameters will still be available.

Considerations: - Ensure that the 'ParseForm' method is not called before any other method that might consume the request body, as the request body is typically read-only once.

func (*Context) PathValue

func (c *Context) PathValue(key string) StringValue

PathValue retrieves a value from the path parameters of an HTTP request based on the given key. The path parameters are typically extracted from the URL path, where they are defined by the routing patterns used in the application.

Parameters: - 'key': A string representing the name of the path parameter to be retrieved.

The function performs the following actions:

  1. It checks if the map 'c.PathParams' contains the key provided in the method parameter. 'c.PathParams' is expected to be populated with key-value pairs where keys correspond to path parameter names defined in the URL pattern, and values are the respective parameters extracted from the actual request URL.
  2. If the key is present in 'c.PathParams', it retrieves the corresponding value, wraps it in a 'StringValue' struct by setting the 'val' field to the retrieved value and 'err' field to nil, and then returns it.
  3. If the key is not found, it means the requested path parameter is not present in the request URL. In this case, the method returns a 'StringValue' struct with 'val' set to an empty string and 'err' set to an error instance that typically indicates the absence of the key.

Return Value:

  • A 'StringValue' struct that contains the value associated with the provided key ('val') and an error field ('err'). If the key is not present, the 'err' field contains an appropriate error while 'val' is an empty string.

Usage: - This method is useful in web server routing where URL paths may contain parameters that need to be extracted and used within the application logic.

Example: - Assuming a URL pattern like "/users/:id" where :id is a path parameter:

userID := c.PathValue("id")
if userID.err != nil {
   // handle the error (e.g., send an HTTP 404 Not Found response)
}
// Use userID.val as the required user ID string value.

Note:

  • The method assumes that 'c.PathParams' has already been populated with the correct path parameters before calling 'PathValue'. In a typical web server implementation, this population is done during the routing process, before the request handler is invoked.
  • The 'PathParams' may hold multiple path parameters depending on the URL pattern; 'PathValue' method is responsible for extracting a single parameter by key.
  • If the same key would be present multiple times in 'c.PathParams', this method would return the first instance of the value associated with the key.

Considerations:

  • When working with frameworks or routers that facilitate path parameter extraction, ensure the router is correctly configured to parse and store the path parameters before calling this method.

func (*Context) QueryValue

func (c *Context) QueryValue(key string) StringValue

QueryValue retrieves the first value associated with the specified key from the URL query parameters of an HTTP request.

Parameters: - 'key' is the string that specifies the key in the query parameter that we want to retrieve the value for.

This function operates as follows:

  1. Checks if 'c.queryValues' is already populated. If it is not, it initializes it with the parsed query parameters obtained by calling 'c.Request.URL.Query()'. This method parses the raw query from the URL and returns a map of the query parameters.
  2. It looks for the given 'key' in 'c.queryValues' to see if it exists. The values are stored in a slice of strings because URL query parameters can have multiple values.
  3. If the key does not exist in the map, it implies that the parameter was not supplied in the query string. In this case, the function returns a 'StringValue' struct with an empty string for the 'val' field and an 'ErrKeyNil' error for the 'err' field.
  4. If the key is present, the function returns a 'StringValue' struct with the first value associated with the key and 'nil' for the 'err' field.

Return Value:

  • A 'StringValue' struct is always returned. It contains: a. 'val', the value associated with the provided key from the query parameters. b. 'err', an error if the key is not found in the query parameters.

Usage: - The method is ideal when you need to obtain individual query parameters from an HTTP request without parsing the entire URL query string manually.

Example: - To retrieve a query parameter named "page" from an HTTP request:

page := c.QueryValue("page")
if page.err != nil {
   // handle the error (e.g., the "page" query parameter was not provided)
}
// Use page.val to work with the value of "page".

Note:

  • This function only retrieves the first value for the specified key even if there are multiple values for that key.
  • 'c.queryValues' is cached after its first use, which improves performance when accessing multiple query parameters since it avoids reparsing the query string of the URL.
  • It is important to correctly handle the error scenario since a missing key in the query parameters can affect application logic.

Considerations: - While handling query data, consider the URL's sensitivity and the possibility of multiple values. Always validate and clean data from URL queries to ensure security.

func (*Context) Render

func (c *Context) Render(templateName string, data any) error

Render processes a template and populates it with dynamic data provided by the 'data' parameter. The method first attempts to render the specified template by calling the rendering engine bound to the context.

Parameters:

  • 'templateName' is the name of the template that should be rendered. It is expected that this template has been defined and is recognizable by the template engine.
  • 'data' is an interface{} type, which means it can accept any value that conforms to Go's empty interface. This is the dynamic content that will be injected into the template during rendering.

The rendered template output is captured and assigned to 'c.RespData'. This output will typically be HTML or another text format suitable for the client's response.

If the rendering operation is successful, the response status code is set to HTTP 200 (OK) indicating the request has been successfully processed and the client can expect valid content.

If an error occurs during the rendering operation (such as if the template is not found, or if there is a problem with the template's syntax), the response status code is set to HTTP 500 (Internal Server Error), and the error is returned to the caller. This error should be handled appropriately by the caller, possibly by logging it or presenting a user-friendly error message to the end-user.

Return Value: Returns 'nil' if rendering succeeds without any error, otherwise an error object describing the rendering failure is returned.

func (*Context) RespJSON

func (c *Context) RespJSON(status int, val any) error

RespJSON sends a JSON-formatted response to the client with a specified HTTP status code. It converts the provided value to JSON, sets the response headers, and writes the JSON data to the response.

Parameters:

  • 'status' is an integer that represents the HTTP status code to send with the response. Standard HTTP status codes should be used (e.g., 200 for OK, 400 for Bad Request, 404 for Not Found, etc.).
  • 'val' is an interface{} (any type) that holds the data to be serialized into JSON. This can be any Go data structure such as structs, slices, maps, etc. The value provided must be a valid input for the json.Marshal function, which means it should be able to be encoded into JSON. Non-exported struct fields will be omitted by the marshaller.

This function performs several actions:

  1. It uses the 'json.Marshal' function to serialize the 'val' parameter into a JSON-formatted byte slice 'data'. If marshaling fails, it returns the resultant error without writing anything to the response.
  2. Assuming marshaling is successful, it sets the "Content-Type" header of the response to "application/json" to inform the client that the server is returning JSON-formatted data.
  3. It sets the "Content-Length" header to the length of the serialized JSON data, which helps the client understand how much data is being transmitted.
  4. It writes the HTTP status code to the response using WriteHeader(status). This must be done before writing the response body.
  5. Lastly, it assigns the JSON data to 'c.RespData' and the status code to 'c.RespStatusCode' for later use or inspection.

Return Value: - If the JSON serialization and writing to the response are successful, it returns 'nil', indicating that the operation completed without error. - If an error occurs during JSON serialization, the error is returned, and no further action is taken.

Usage: - This method is designed to be used in HTTP handler functions where a JSON response is needed. It abstracts away the common tasks of JSON serialization, header setting, and response writing.

Example: - To send an object with an OK (200) status code:

data := map[string]string{"status": "success"}
err := c.RespJSON(http.StatusOK, data)
if err != nil {
   log.Printf("Error sending JSON response: %v", err)
   // handle the error, like sending a 500 Internal Server Error status code
}

Note:

  • It is important to note that once the 'WriteHeader' method is called, it's not possible to change the response status code or write any new headers. Also, care must be taken to ensure that 'RespJSON' is not called after the response body has started to be written by other means, as this would result in an HTTP protocol error.

func (*Context) RespJSONOK

func (c *Context) RespJSONOK(val any) error

RespJSONOK sends a JSON response with an HTTP status code 200 (OK) to the client. This is a convenience method that wraps around the more general 'RespJSON' method, abstracting the common case of responding with an OK status.

Parameters:

  • 'val' is the data of any type that will be serialized into JSON format. The 'val' can be any Go data structure, including structs, maps, slices, and primitive types. It is important that the 'val' can be marshaled into JSON; otherwise, the serialization will fail.

Internally, 'RespJSONOK' calls the 'RespJSON' method on the same context instance 'c', passing in 'http.StatusOK' as the status code and 'val' as the value to be serialized.

The 'RespJSON' method handles the serialization of 'val' to JSON, sets the "Content-Type" response header to "application/json", and writes the JSON-encoded data to the response along with the provided HTTP status code.

Return Value: - If the serialization into JSON is successful and the response is written to the client, it returns 'nil' indicating no error occurred. - In case of an error during JSON marshaling or writing to the response, it returns an error detailing the issue encountered.

Usage:

  • This method is typically used within an HTTP handler function when the server needs to send a JSON response back to the client with a 200 OK status code. This is usually the case when a request has been processed successfully, and server needs to inform the client of the success, often with accompanying data.

Example: - To send a simple success message in JSON format:

type response struct {
   Message string `json:"message"`
}

resp := response{Message: "Data processed successfully"}
err := c.RespJSONOK(resp)
if err != nil {
   // handle error
}

Note: - This method should be called after all response headers and status codes are set, and before any calls to write body content directly, as it will write data to the body and set headers.

func (*Context) SetCookie

func (c *Context) SetCookie(ck *http.Cookie)

SetCookie adds a Set-Cookie header to the response of the current HTTP context. This method is used to send cookies from the server to the client's web browser.

Parameters: - 'ck' is a pointer to an 'http.Cookie' object which represents the cookie you want to set. This object includes various fields that define the properties of a cookie, such as Name, Value, Path, Domain, Expires, and so on.

This function does not return any value or error, as it directly manipulates the HTTP headers of the response. It's essential to call SetCookie before writing any response body to the client because HTTP headers cannot be modified after the body starts to be written.

'http.SetCookie' is a standard library function that ensures the correct formatting of the Set-Cookie header. When calling this method, 'c.ResponseWriter' is used to gain access to the response writer associated with the current HTTP request handled by the context 'c'.

Usage:

  • This method is typically called within an HTTP handler function where you have an instance of the Context 'c' available. It is part of managing session data, sending tracking cookies, or setting any other kind of cookie data required by the application.

Example: - To set a session cookie with a session identifier:

sessionCookie := &http.Cookie{
   Name:    "session_id",
   Value:   "abc123",
   Expires: time.Now().Add(24 * time.Hour),
   Path:    "/",
}
c.SetCookie(sessionCookie)

Note: - If you need to set multiple cookies, you would call this method multiple times, passing in each cookie as a separate 'http.Cookie' object.

type FileDownloader

type FileDownloader struct {
	Dir string
}

FileDownloader is a structure that encapsulates the necessary information for handling file download operations in a web application setting. The struct is designed to provide a foundation for methods that allow users to download files from a specified directory on the server. It acts primarily as a configuration container for the download directory, with the potential to extend functionality for more advanced features like path resolution, access control, and download logging.

Fields:

  • Dir string: Specifies the root directory from which files will be served. This path should be an absolute path or a relative path to the directory that the server process has access to. All file download requests will be resolved relative to this directory, meaning that file paths provided in download requests should be relative to this 'Dir' directory. It is important to consider security implications when defining this directory, to prevent unauthorized access to sensitive files. File access should be properly managed to avoid directory traversal attacks or the exposure of restricted files.

Usage Notes: An instance of FileDownloader should be initialized with the 'Dir' field set to the directory containing the files to be downloaded. This instance can then be integrated into the web application's server side, where a corresponding handler function will use the information contained within FileDownloader to resolve and serve file download requests. The handler will typically interpret the file path from the incoming HTTP request, ensure that it points to a valid file within the 'Dir', and then stream that file back to the client with the appropriate Content-Disposition header to prompt a file download in the client's browser.

Example Implementation:

downloader := &FileDownloader{
    Dir: "/var/www/downloads",
}

This downloader instance could then be referenced in a dedicated route's handler function to process file download requests, ensuring all downloads are served from the "/var/www/downloads" directory.

func (*FileDownloader) Handle

func (f *FileDownloader) Handle() HandleFunc

Handle creates and returns a HandleFunc designed for serving files for download. This HTTP handler ensures that the files served for download are securely retrieved from a specified server directory and delivered to the client correctly. The handler takes care to resolve the file path, validate the request, and to set proper HTTP headers to facilitate the file download on the client side.

The HandleFunc performs the following steps:

  1. Extracts the 'file' query parameter from the request's URL. This parameter contains the relative path to the file that the client wants to download.
  2. If the 'file' query parameter is missing or another error occurs while retrieving it, the handler responds with an HTTP 400 Bad Request status and a message indicating that the destination file could not be found.
  3. Cleans up the requested file path using filepath.Clean to prevent any directory traversal attempts and ensure the path is in its simplest form.
  4. Joins the cleaned file path with the FileDownloader's Dir to form an absolute path to the file within the server's file system.
  5. Converts the resulting path to an absolute path and checks if the resolved file path actually exists within the designated download directory. This acts as a security measure to prevent clients from accessing files outside the allowed directory.
  6. If the resolved file path is outside the designated download directory, the handler responds with an HTTP 400 Bad Request status and a message indicating an access path error.
  7. The file name is extracted from the resolved path to be used in the Content-Disposition header, which advises the client's browser that a file is expected to be downloaded and saved locally.
  8. Various HTTP response headers are set to inform the client about the file transfer details: - Content-Disposition: Advises the client on how to handle the file data. - Content-Description: Description of the content. - Content-Type: Specifies that the content is a stream of binary data (i.e., a file). - Content-Transfer-Encoding: Notates that the content transfer will be in binary mode. - Expires: Indicates that the content should not be cached for later use. - Cache-Control and Pragma: Directives to control browser caching.
  9. The http.ServeFile function is called to serve the file contained in the resolved path to the client. This function takes care of streaming the file data to the client. The function also automatically determines the Content-Type header, although it is overridden here to "application/octet-stream" to trigger the browser's download dialog.

The handler secured by the FileDownloader ensures that only files from a specified directory can be accessed and downloaded by the client. Proper error handling is implemented to return meaningful HTTP status codes and messages to the client in case of an error, such as path resolution issues or illegal file access attempts.

type FileUploader

type FileUploader struct {
	FileField   string
	DstPathFunc func(*multipart.FileHeader) string
}

FileUploader defines a structure used for configuring and handling the upload of files in a web application. It provides a customized way of determining where files should be stored upon upload based on the properties provided. It is particularly useful in scenarios where uploaded files need to be saved to different locations depending on file metadata or other contextual information available at runtime.

Fields:

  • FileField string: The name of the form field used for the file upload. This corresponds to the 'name' attribute in the HTML form input element for file uploads (e.g., <input type="file" name="myfile">). The FileUploader will look for this specific field in the multipart form data to process the file uploads.

  • DstPathFunc func(*multipart.FileHeader) string: A functional field used to generate the destination path for an uploaded file. This function takes a pointer to a multipart.FileHeader struct, which contains metadata about an uploaded file (such as filename, size, and content type), and returns a string that represents the destination path where the file should be saved. By allowing the path to be dynamically determined through this function, the FileUploader can achieve more flexible and context-sensitive file storage behavior. This is advantageous when the storage location depends on specific file characteristics or other request-specific data.

Example usage of FileUploader:

uploader := &FileUploader{
    FileField: "avatar", // This should match the file input field's name in your form
    DstPathFunc: func(fh *multipart.FileHeader) string {
        // Generate a unique file name, for instance, by using a UUID generator, and sanitize the original filename
        // Colons could be replaced with a timestamp or another identifier as needed for the application.
        return filepath.Join("/uploads/avatars", uuid.New().String() + filepath.Ext(fh.Filename))
    },
}

The FileUploader struct is typically used in conjunction with HTTP server handlers or middlewares in Go that are responsible for handling file uploads. During the request processing, the FileUploader can be utilized to retrieve the file data associated with its FileField and to invoke DstPathFunc to calculate where the file should be stored. Subsequent steps would typically involve actually storing the file data in the specified location and handling any errors or post-processing tasks as necessary.

func (*FileUploader) Handle

func (f *FileUploader) Handle() HandleFunc

Handle returns a HandleFunc specifically prepared to process file upload requests based on the configuration of the FileUploader struct. This HandleFunc can be used as an HTTP handler that intercepts file upload HTTP requests, processes them, and provides an appropriate response to the client based on the outcome of the operation.

The returned HandleFunc performs the following steps:

  1. It attempts to retrieve the file data from the request's form field as specified by the FileUploader's FileField.
  2. If it encounters an error during file retrieval, it sets the HTTP response status code to Internal Server Error (500), and it sends back an error message to the client, indicating that the upload failed, along with the error details.
  3. Upon successful retrieval of the file, the function then calls the FileUploader's DstPathFunc with the metadata of the uploaded file (fileHeader) to determine the destination path where the file should be saved.
  4. The function checks for errors from the DstPathFunc call; if there's an error, it responds with an Internal Server Error status and an error message as in step 2.
  5. Next, it attempts to open (or create if not existing) the destination file for writing. It ensures that the permissions for the new file allow read and write operations for the user, group, and others (permission mode 0666).
  6. If it cannot open the destination file, it responds with an Internal Server Error status and an error message.
  7. If the destination file is opened successfully, it then copies the content of the uploaded file to the destination file using an io.CopyBuffer operation. This function performs the copy operation and allows the reuse of an existing slice (buffer) to reduce memory allocation, which is set to nil to use a pre-allocated buffer of a default size.
  8. Any error encountered during the copy process results in an Internal Server Error status and an error message.
  9. If the file is uploaded and saved successfully, the function sets the HTTP response status to OK (200) and sends a success message to the client.

It's important that the file handles for both the uploaded file and the destination file are closed properly to release the resources. The defer keyword is used right after each file is opened to ensure that the file handles are closed when the function returns.

Usage of the Handle method would typically involve adding the returned HandleFunc as an HTTP handler in a web server's routing configuration. This would route certain POST requests expected to contain file uploads through this handler to process the file saving task accordingly.

type GoTemplateEngine

type GoTemplateEngine struct {
	// T is a pointer to a compiled template object from the Go standard library's template package.
	// It stores all the parsed template files that can be executed to generate output based on dynamic data.
	T *template.Template
}

GoTemplateEngine is a struct that adheres to the TemplateEngine interface. It represents a concrete implementation using Go's standard library "text/template" or "html/template" for rendering templates. This structure enables the application to perform template rendering operations using Go's built-in template parsing and execution capabilities.

The GoTemplateEngine struct contains a single field:

  • T: This field holds a pointer to a template.Template object from Go's template package. The template.Template type is a thread-safe, compiled representation of a set of templates that can be executed with particular data inputs to produce rendered content. This field should be pre-populated with parsed templates upon the creation of a GoTemplateEngine instance.

When initializing a new GoTemplateEngine, the typical process includes parsing the template files or strings using the Parse, ParseFiles, or ParseGlob functions provided by Go's template package. These functions compile the templates and return a *template.Template object, which is then assigned to the T field.

Using the T field, the GoTemplateEngine can execute the named templates with given data using the ExecuteTemplate method, which satisfies the Render method of the TemplateEngine interface. The execution process replaces template tags with corresponding data and generates the final rendered output.

Example of initializing a GoTemplateEngine with parsed templates could look like this:

func NewEngine() (*GoTemplateEngine, error) {
    tmpl, err := template.ParseFiles("templates/base.html", "templates/index.html")
    if err != nil {
        return nil, err
    }
    return &GoTemplateEngine{T: tmpl}, nil
}

func (*GoTemplateEngine) LoadFromFS

func (g *GoTemplateEngine) LoadFromFS(fs fs.FS, patterns ...string) error

LoadFromFS is a method on the GoTemplateEngine struct that loads and parses templates from a file system abstraction (fs.FS) using specified glob patterns. It updates the GoTemplateEngine's T field with the resulting template set. This allows the loading of templates from various sources that implement the fs.FS interface, such as in-memory file systems, making the method flexible and adaptable to different run-time environments.

Parameters:

  • fs.FS: The fs.FS interface instance represents an abstract file system to load templates from. It provides a way to abstract the file system operations through methods like Open, making it possible to work with different file systems (e.g., an actual OS file system, in-memory file systems, embedded file systems).
  • patterns ...string: This variadic parameter takes multiple string arguments, each representing a glob pattern used to match files within the provided file system (fs). These patterns tell the method which files to consider when loading and parsing the templates.

Returns:

  • error: If there is an issue parsing the templates using the provided file system and patterns, the method will return an error. This error could be a result of file I/O operations issues, files not matching any patterns, permission issues, or problems within the template files such as syntax errors. In the case of an error, the GoTemplateEngine's T field will not be updated with any new templates.

Internally, the method uses the template.ParseFS function from Go's template package. This function is designed to work with the fs.FS interface to read and parse templates. The method parses all the files that match the provided patterns into a template set, which is then stored in the T field of the current GoTemplateEngine instance.

As with other template loading methods, proper error handling is crucial to ensure the application can handle cases where templates could not be loaded. If no errors are returned, the engine can proceed to render these templates through its Render method, as they are immediately available for use.

func (*GoTemplateEngine) LoadFromFiles

func (g *GoTemplateEngine) LoadFromFiles(filenames ...string) error

LoadFromFiles is a method on the GoTemplateEngine struct that parses template files specified by the filenames and updates the GoTemplateEngine's T field with the parsed template set. This method allows for explicit control over which template files are loaded and is commonly used for initializing the engine with a known set of templates or updating the templates at runtime.

Parameters:

  • filenames ...string: A variadic parameter that accepts an arbitrary number of strings, each representing the path to a template file that should be included in the parsing process. This allows for a flexible number of files to be loaded at once without needing to specify them in a slice.

Returns:

  • error: If the method encounters any issues while trying to read or parse the provided template files, it will return an error. Potential issues include file I/O errors, file not found errors, permission denials, or problems within the template files themselves, such as syntax errors. If an error is returned, the T field remains unchanged, and the new templates are not loaded.

The method makes use of the template.ParseFiles function provided by Go's template package. The ParseFiles function takes the provided file paths, reads the contents, and attempts to parse them into templates within a template set. These templates are then stored in the T field of the GoTemplateEngine.

Error handling after calling this method is essential to ensure the application's stability, as templates are fundamental for generating output based on them. On successful execution, the templates become immediately available for rendering through the engine's Render method.

func (*GoTemplateEngine) LoadFromGlob

func (g *GoTemplateEngine) LoadFromGlob(pattern string) error

LoadFromGlob is a method of GoTemplateEngine that loads and parses template files based on a specified pattern (glob). After execution, the GoTemplateEngine's T field is updated to contain the new parsed templates. This method is typically used during initialization or when the templates need to be refreshed.

Parameter:

  • pattern string: The pattern parameter is a string that specifies the glob pattern used to identify the template files that should be parsed and added to the template set. A glob pattern may include wildcards (e.g., "*.tmpl" for all files with the .tmpl extension in the current directory, or "templates/*.html" for all .html files within a 'templates' directory).

Returns:

  • error: This function will return an error if the parsing operation fails. The error might be caused by an inability to read files due to incorrect permissions, non-existent files, or syntax errors within the template files themselves. If an error is returned, the T field of the GoTemplateEngine struct is not updated with any new templates.

The method works by invoking template.ParseGlob from Go's template package with the provided pattern string. This function reads and parses all the template files that match the pattern into a new template set. The parsed templates are then assigned to the T field of the GoTemplateEngine instance.

When calling this method, it's important to handle any errors returned to ensure the application is aware if the templates failed to load. A successful execution means that the T field is now ready to execute the loaded templates with the Render method.

func (*GoTemplateEngine) Render

func (g *GoTemplateEngine) Render(ctx context.Context, templateName string, data any) ([]byte, error)

Render is the method that implements the rendering functionality for the GoTemplateEngine. It satisfies the TemplateEngine interface's Render method, allowing the GoTemplateEngine to be used wherever a TemplateEngine is required. This method executes the named template using the provided data and generates a rendered output as a slice of bytes.

Parameters:

  • ctx context.Context: This parameter provides context for the render operation. It can carry deadlines, cancellations signals, and other request-scoped values across API boundaries and between processes. In this method, ctx is not directly used but could be utilized by extending the method further to support context-aware operations in the render process, such as logging, tracing, timeout, or cancellation.
  • templateName string: The name of the template to be executed. This must correspond to the name given to one of the parsed templates contained within the *template.Template associated with the GoTemplateEngine.
  • data any: The data to be applied to the template during rendering. This could be any type of value that the underlying templates are expected to work with, typically a struct, map, or a primitive type that the template fields can reference.

Returns:

  • []byte: A byte slice containing the rendered output from the executed template. If rendering is successful without any errors, the content of the slice represents the completed output, ready to be used as needed (e.g., sent as an HTTP response).
  • error: An error that may have been encountered during the template execution. If such an error occurs, it's usually related to issues like an undefined template name, missing data for placeholders in the template, or execution errors within the template. If the error is non-nil, the byte slice returned will be nil, and the error should be handled appropriately.

The Render method works by creating a new bytes.Buffer to act as an in-memory writer where the rendered output is temporarily stored. The ExecuteTemplate method of the *template.Template is then called with this buffer, the name of the template, and the data to be used for rendering. If the template execution is successful, the content of the buffer is returned as a byte slice. In case of an error, the error returned from ExecuteTemplate is passed through to the caller.

type HTTPServer

type HTTPServer struct {
	// contains filtered or unexported fields
}

HTTPServer defines the structure of an HTTP server with routing capabilities, middleware support, logging functionality, and a template engine for rendering HTML templates.

Fields:

  • router: Embeds the routing information which includes the tree of routes and handlers that the server uses to match incoming requests to their respective handlers.

  • mils []Middleware: A slice that holds the globally applied middleware. These middleware functions are executed for every request in the order they are added. They can be used to modify the http.Handler behaviour, perform actions such as logging, authentication etc.

  • log func(msg string, args ...any): A function for logging where msg is a formatted log message and args are optional arguments which may be included in the formatted output. Developers can use this to output relevant log information or to integrate third-party logging libraries.

  • templateEngine: An interface that represents the template engine used by the server to render HTML templates. This allows for dynamic HTML content generation based on data models and can be customized by the developer to use the desired templating system.

Usage: An instance of HTTPServer typically starts by configuring routes, middleware, and the template engine. Once set up, the server can handle HTTP requests, match them to their designated handlers, and generate dynamic responses. Logging is facilitated through the provided log function, enabling tracking of server activity and diagnosing issues.

func InitHTTPServer

func InitHTTPServer(opts ...HTTPServerOption) *HTTPServer

InitHTTPServer initializes and returns a pointer to a new HTTPServer instance. The server can be customized by passing in various HTTPServerOption functions, which will modify the server's configuration according to the functionalities encapsulated by those options. This pattern is known as the "functional options" pattern and allows for flexible and readable server configuration without the need for a potentially long list of parameters.

Parameters:

  • opts: A variadic array of HTTPServerOption functions. Each one is applied to the HTTPServer instance and can set or modify configurations such as middlewares, logging, server address, timeouts, etc.

The InitHTTPServer function operates in the following steps:

  1. Creates a new HTTPServer instance with some initial default settings. a. A router is initialized for the server to manage routing of incoming requests. b. A default logging function is set up to print messages to standard output, which can be overridden by an option.
  2. Iterates through each provided HTTPServerOption, applying it to the server instance. These options are functions that accept a *HTTPServer argument and modify its properties, thereby customizing the server according to the specific needs of the application.
  3. After applying all options, the function returns the customized HTTPServer instance, ready to be started and to begin handling incoming HTTP requests.

This initialization function abstracts away the complexity of server setup and allows developers to specify only the options relevant to their application, leading to cleaner and more maintainable server initialization code.

func (*HTTPServer) CONNECT added in v0.0.10

func (s *HTTPServer) CONNECT(path string, handleFunc HandleFunc)

CONNECT registers a new route with an associated handler function for handling HTTP CONNECT requests. The HTTP CONNECT method is utilized primarily for establishing a tunnel to a server identified by a given URI.

Parameters:

  • path string: The endpoint or route pattern where the server will listen for incoming CONNECT requests. This may include parameter placeholders that can be used to extract values from the URL during request handling.
  • handleFunc: A callback function that is invoked in response to a CONNECT request to the given path. This function has access to the request and response through a *Context, providing the necessary tools to implement the tunneling behavior or other custom logic expected on a CONNECT request.

Example usage:

s.Connect("/proxy", func(ctx *Context) {
    // Logic to establish a proxy connection.
})

Note: The use of `http.MethodConnect` ensures that only HTTP CONNECT requests are matched to this handler, facilitating the appropriate processing logic for these specialized request types, which are different from the standard GET, POST, PUT, etc., methods.

func (*HTTPServer) DELETE added in v0.0.10

func (s *HTTPServer) DELETE(path string, handleFunc HandleFunc)

DELETE registers a new route with an associated handler function for HTTP DELETE requests. This method is used to remove a resource identified by a URI.

Parameters:

  • path string: The URL pattern that the server will listen on for incoming DELETE requests. This parameter defines the endpoint at which the handler will be called when a DELETE request matches the path.
  • handleFunc: A function that is called when a DELETE request is made to the registered path. This function should contain the logic to handle the deletion of a resource, and it is provided with a *Context object to interact with the request and response data.

Example usage:

s.Delete("/users/{id}", func(ctx *Context) {
    // Handler logic to delete a user resource with the given ID.
})

Note: Using `http.MethodDelete` in the call to registerRoute confines this handler to respond solely to DELETE requests, providing a way to define how the server handles deletions.

func (*HTTPServer) GET added in v0.0.10

func (s *HTTPServer) GET(path string, handleFunc HandleFunc)

GET registers a new route and its associated handler function for HTTP GET requests. This method is a shortcut for registering routes that should only respond to GET HTTP method, typically used for retrieving resources.

Parameters:

  • path string: The URL pattern to match against incoming requests. The route pattern can contain parameters that will be parsed from the URL and made available to the handler function during request handling.
  • handleFunc: The function to be called when a request matching the path is received. The handler function is defined to take a *Context as its only parameter, through which it can access the request data and send a response back.

Example usage:

s.Get("/home", func(ctx *Context) {
    // Handler logic for the `/home` path when an HTTP GET request is received
})

Note: The method internally calls registerRoute to add the route to the server's routing table with the method specified as `http.MethodGet`, which ensures that only GET requests are handled by the provided handler.

func (*HTTPServer) HEAD added in v0.0.10

func (s *HTTPServer) HEAD(path string, handleFunc HandleFunc)

HEAD registers a new route and its associated handler function for HTTP HEAD requests. This method is used to handle requests where the client is interested only in the response headers, and not the actual body of the response, which is typical behavior of a HEAD request in HTTP.

Parameters:

  • path string: The path pattern to which the route will respond. When a HEAD request to this pattern is received, the registered handler function will be executed.
  • handleFunc: The handler function that will be associated with the provided path pattern. This function will be called with a *Context parameter that contains information about the request and mechanisms to construct a response.

Example usage:

s.Head("/resource", func(ctx *Context) {
    // Handler logic to return response headers for the '/resource' path
    // without returning the actual body.
})

Note: The method utilizes the registerRoute internal function to add the route to the server's routing table specifically for the HEAD HTTP method, which ensures that only HEAD requests will trigger the execution of the provided handler function.

func (*HTTPServer) OPTIONS added in v0.0.10

func (s *HTTPServer) OPTIONS(path string, handleFunc HandleFunc)

OPTIONS registers a new route with an associated handler function for HTTP OPTIONS requests. The HTTP OPTIONS method is used to describe the communication options for the target resource.

Parameters:

  • path string: The URL pattern that the server will match against incoming OPTIONS requests. Defining the endpoint allows clients to find out which methods and operations are supported at a given URL or server.
  • handleFunc: The function to be executed when an OPTIONS request is received. It typically provides information about the HTTP methods that are available for a particular URL endpoint. The handleFunc is supplied with a *Context object to facilitate interaction with the HTTP request and response.

Example usage:

s.Options("/articles/{id}", func(ctx *Context) {
    // Handler logic to indicate supported methods like GET, POST, PUT on the article resource.
})

Note: This registration only affects OPTIONS requests due to the use of `http.MethodOptions`. It is standard practice to implement this method on a server to inform clients about the methods and content types that the server is capable of handling, thereby aiding the client's decision-making regarding further actions.

func (*HTTPServer) PATCH added in v0.0.10

func (s *HTTPServer) PATCH(path string, handleFunc HandleFunc)

PATCH registers a new route with an associated handler function for HTTP PATCH requests. This method is generally used for making partial updates to an existing resource.

Parameters:

  • path string: The pattern of the URL that the server will match against incoming PATCH requests. The path can include variables that will be extracted from the URL and passed to the handler.
  • handleFunc: The function to execute when the server receives a PATCH request at the specified path. This function is provided with a *Context object, enabling access to request information and response functionalities.

Example usage:

s.Patch("/profile/{id}", func(ctx *Context) {
    // Handler logic to apply partial updates to a profile based on the ID in the URL.
})

Note: Registering the route with the `http.MethodPatch` constant ensures that only PATCH requests are handled by the provided function. The PATCH method is typically used to apply a partial update to a resource, and this function is where you would define how the server handles such requests.

func (*HTTPServer) POST added in v0.0.10

func (s *HTTPServer) POST(path string, handleFunc HandleFunc)

POST registers a new route and its associated handler function for handling HTTP POST requests. This method is used for routes that should accept data sent to the server, usually for the purpose of creating or updating resources.

Parameters:

  • path string: The URL pattern to match against incoming POST requests. It defines the endpoint at which the handler function will be called for incoming POST requests.
  • handleFunc: The function to be executed when a POST request is made to the specified path. It receives a *Context object that contains the request information and provides the means to write a response back to the client.

Example usage:

s.Post("/submit", func(ctx *Context) {
    // Handler logic for processing the POST request to the `/submit` path.
})

Note: The method delegates to registerRoute, internally setting the HTTP method to `http.MethodPost`. This ensures that the registered handler is invoked only for POST requests matching the specified path.

func (*HTTPServer) PUT added in v0.0.10

func (s *HTTPServer) PUT(path string, handleFunc HandleFunc)

PUT registers a new route and its associated handler function for handling HTTP PUT requests. This method is typically used to update an existing resource or create a new resource at a specific URL.

Parameters:

  • path string: The URL pattern to which the server should listen for PUT requests. This pattern may include placeholders for dynamic segments of the URL, which can be used to pass variables to the handler function.
  • handleFunc: A callback function that will be invoked when a PUT request is made to the specified path. The function takes a *Context parameter that provides access to the request data and response writer.

Example usage:

s.Put("/items/{id}", func(ctx *Context) {
    // Handler logic for updating an item with a particular ID using a PUT request.
})

Note: By calling registerRoute and specifying `http.MethodPut`, this method ensures that the handler is specifically associated with PUT requests. If a PUT request is made on the matched path, the corresponding handler function will be executed.

func (*HTTPServer) ServeHTTP

func (s *HTTPServer) ServeHTTP(writer http.ResponseWriter, request *http.Request)

ServeHTTP is the core method for handling incoming HTTP requests in the HTTPServer. This method fulfills the http.Handler interface, making an HTTPServer instance compatible with Go's built-in HTTP server machinery. ServeHTTP is responsible for creating the context for the request, applying middleware, and calling the final request handler. After the request is processed, it ensures that any buffered response (if applicable) is flushed to the client.

Parameters: - writer: An http.ResponseWriter that is used to write the HTTP response to be sent to the client. - request: An *http.Request that represents the client's HTTP request being handled.

The ServeHTTP function operates in the following manner:

  1. It begins by creating a new Context instance, which is a custom type holding the HTTP request and response writer, along with other request-specific information like the templating engine.
  2. It retrieves the root handler from the server's configuration 's.server', which represents the starting point for the request handling pipeline.
  3. Iteratively wraps the root handler with the server's configured middleware in reverse order. Middleware is essentially a chain of functions that can execute before and/or after the main request handler to perform tasks such as logging, authentication, etc.
  4. Introduces a final middleware that calls the next handler in the chain and then flushes any buffered response using 's.flashResp'. This ensures that even if a response is buffered (for performance reasons or to allow for manipulations), it gets sent out after the request is processed.
  5. Calls the fully wrapped root handler, beginning the execution of the middleware chain and ultimately invoking the appropriate request handler.

func (*HTTPServer) Start

func (s *HTTPServer) Start(addr string) error

Start initiates the HTTP server listening on the specified address. It sets up a TCP network listener on the given address and then starts the HTTP server to accept and handle incoming requests using this listener. If there is a problem creating the network listener or starting the server, it returns an error.

Parameters:

  • addr: A string specifying the TCP address for the server to listen on. This typically includes a hostname or IP followed by a colon and the port number (e.g., "localhost:8080" or ":80"). If only the port number is specified with a leading colon, the server will listen on all available IP addresses on the given port.

The Start function operates in the following manner:

  1. Calls net.Listen with "tcp" as the network type and the provided address. This attempts to create a listener that can accept incoming TCP connections on the specified address.
  2. If net.Listen returns an error, it is immediately returned to the caller, indicating that the listener could not be created (possibly due to an invalid address, inability to bind to the port, etc.).
  3. If the listener is successfully created, the function then calls http.Serve with the listener and the server itself as arguments. This starts the HTTP server, which begins listening for and handling requests. The server will use the ServeHTTP method of the HTTPServer to process each request.
  4. If http.Serve encounters an error, it will also be returned to the caller. This can happen if there's an unexpected issue while the server is running, such as a failure to accept a connection.

The Start method is a blocking call. Once called, it will continue to run, serving incoming HTTP requests until an error is encountered or the server is manually stopped.

func (*HTTPServer) TRACE added in v0.0.10

func (s *HTTPServer) TRACE(path string, handleFunc HandleFunc)

TRACE registers a new route with an associated handler function for HTTP TRACE requests. The HTTP TRACE method is used to echo back the received request so that a client can see what (if any) changes or additions have been made by intermediate servers.

Parameters:

  • path string: The endpoint on the server that will respond to the TRACE requests. This defines the path pattern that must be matched for the handler function to be invoked.
  • handleFunc: A function that handles the TRACE request. It should process the request and typically returns the same request message in the response body. This function has a *Context object allowing access to the request details and the ability to write the response.

Example usage:

s.Trace("/echo", func(ctx *Context) {
    // Handler logic that echoes the incoming request back to the client.
})

Note: Registering this route specifically listens for HTTP TRACE requests by using `http.MethodTrace`. This is helpful for debugging purposes where the client needs to understand what headers and body are being received by the server after any possible alterations by intermediate devices.

func (*HTTPServer) Use

func (s *HTTPServer) Use(mils ...Middleware)

Use attaches the provided middlewares to the existing set of middlewares in the HTTPServer instance. If no middleware has been set yet, it initializes the middleware list with the provided ones. If there are already middlewares present in the server, it appends the new ones to the end of the middleware chain.

Middlewares are executed in the order they are added to the server, meaning that the order of middlewares can affect the request/response processing. They are commonly used to handle tasks such as request logging, authentication, input validation, error handling, etc.

Usage example:

server := &HTTPServer{}
server.Use(loggingMiddleware)
server.Use(authenticationMiddleware)

Parameters: - mils ...Middleware : One or multiple Middleware functions to add to the server's middleware chain.

Note: This method appends provided middlewares variably, allowing for zero or more middlewares to be added at once. If called with no arguments, it will simply do nothing to the current middleware chain.

func (*HTTPServer) UseForAll added in v0.0.5

func (s *HTTPServer) UseForAll(path string, mdls ...Middleware)

UseForAll associates the provided middlewares with all HTTP methods for the specified path. This method configures the HTTP server to apply the given middlewares to every request method (GET, POST, OPTIONS, etc.) for the specified route path. This is useful when you want consistent middleware execution for a path, irrespective of the HTTP method used in the request.

Parameters: - path: The URL pattern to match against incoming request URLs. - mdls: A variadic list of middlewares to be applied to all requests for the route.

Usage:

  • server.UseForAll("/api/resource", loggerMiddleware, authMiddleware) This example would apply the logger and auth middlewares to all request methods for path "/api/resource".

func (*HTTPServer) UseRoute

func (s *HTTPServer) UseRoute(method string, path string, mils ...Middleware)

UseRoute associates a new route with the specified HTTP method and path to the server's routing system. Additionally, it allows for the chaining of middleware functions that can intercept and modify the request or response, or perform specific actions like logging, authentication, etc., before the request reaches the final handler function.

Parameters:

  • method string: The HTTP method (e.g., GET, POST, PUT, DELETE) for which the route is to be registered.
  • path string: The path pattern to be matched against the URL of incoming requests.
  • mils ...Middleware: A variadic parameter that allows passing an arbitrary number of middleware functions. These functions are executed in the order they are provided, prior to the final handler.

Usage: When registering a route, you can specify the HTTP method and path, followed by the series of middleware you wish to apply. If no final handler is provided at the time of route registration, one must be attached later for the route to be functional.

Example usage:

s.UseRoute("GET", "/articles", AuthMiddleware, LogMiddleware)

Here, `AuthMiddleware` would be used to authenticate the request, and `LogMiddleware` would log the request details. A route handler would need to be added subsequently to handle the GET requests for `/articles` path.

Note: This method is used for initial route setup and must be combined with a handler registration to create a complete, functional route. If a handler is not attached later, the route will not have any effect.

type HTTPServerOption

type HTTPServerOption func(server *HTTPServer) // Functional option for configuring an HTTPServer

HTTPServerOption defines a function type used to apply configuration options to an HTTPServer.

Each HTTPServerOption is a function that accepts a pointer to an HTTPServer and modifies it according to some configuration logic. This pattern, often called "functional options", allows for flexible, clear, and safe configurations when constructing an instance of HTTPServer. It enables the programmer to chain multiple configuration options in a declarative way when creating a new server instance or adjusting its settings.

Usage: Developers can define custom HTTPServerOption functions that set various fields or initialize certain parts of the HTTPServer. These options can then be passed to a constructor function that applies them to the server instance.

Example:

func WithTemplateEngine(engine TemplateEngine) HTTPServerOption {
  return func(server *HTTPServer) {
    server.templateEngine = engine
  }
}

func WithMiddleware(middleware ...Middleware) HTTPServerOption {
  return func(server *HTTPServer) {
    server.mils = append(server.mils, middleware...)
  }
}

// When initializing a new HTTPServer:
srv := NewHTTPServer(
  WithTemplateEngine(myTemplateEngine),
  WithMiddleware(AuthMiddleware, LoggingMiddleware),
)

func ServerWithMiddleware

func ServerWithMiddleware(mils ...Middleware) HTTPServerOption

ServerWithMiddleware takes a variadic slice of Middleware functions and returns an HTTPServerOption. This option configures a HTTPServer with the provided middlewares. Middlewares are used to intercept or otherwise modify requests and responses in an HTTP server. Middleware functions are typically used for logging, security controls, rate limiting, etc.

Example of using ServerWithMiddleware to configure an HTTPServer with middlewares:

myServer := NewHTTPServer(
    ServerWithMiddleware(loggingMiddleware, authenticationMiddleware),
)

Parameters: - mils ...Middleware : A variadic slice of Middleware functions to be applied to the server.

Returns:

  • HTTPServerOption : A function that takes an HTTPServer pointer and assigns the provided middlewares to it. This function can be applied as a configuration option when creating an HTTPServer.

func ServerWithTemplateEngine

func ServerWithTemplateEngine(templateEngine TemplateEngine) HTTPServerOption

ServerWithTemplateEngine is a configuration function that returns an HTTPServerOption. This option is used to set a specific TemplateEngine to the HTTPServer, which can then be used to render HTML templates for the client. It's useful when your server needs to deliver dynamic web pages that are generated from templates.

A TemplateEngine is an interface or a set of functionalities that processes templates with given data and produces an HTML output that the HTTP server can send to the client's web browser.

Usage example:

server := NewHTTPServer(
    ServerWithTemplateEngine(myTemplateEngine),
)

Parameters:

  • templateEngine : The template engine to be set on the HTTPServer. This parameter specifies the concrete implementation of a template engine that the server will use for rendering templates.

Returns:

  • HTTPServerOption : A function that configures the server with the specified template engine. When applied as an option to the server, it assigns the 'templateEngine' to the server's internal field for later use.

type HandleFunc

type HandleFunc func(ctx *Context) // Type signature for request handling functions within the framework

HandleFunc defines the function signature for an HTTP request handler specific to your web framework.

This type represents a function that takes a pointer to a Context object as its argument and does not return any value. The Context object typically encapsulates all the information about the current HTTP request, including the request itself, response writer, path parameters, query parameters, and any other metadata or utilities needed to process the request.

Usage: A HandleFunc is intended to be used as a callback for specific routes to handle incoming HTTP requests. Each route will have an associated HandleFunc that will be executed when the route is matched.

Example:

func HelloWorldHandler(ctx *Context) {
  ctx.ResponseWriter.Write([]byte("Hello, World!"))
}

// Registering the handler with a route:
server.registerRoute("GET", "/hello", HelloWorldHandler)

type Middleware

type Middleware func(next HandleFunc) HandleFunc

Middleware represents a function type in Go that defines the structure of a middleware function. In the context of web servers or other request-handling applications, middleware is used to process requests before reaching the final request handler, allowing for pre-processing like authentication, logging, or any other operation that should be performed before or after the main processing of a request.

The type is defined as a function that takes one HandleFunc as its parameter (often referred to as 'next') and returns another HandleFunc. The HandleFunc inside the parentheses is the next function in the chain that the middleware will call, while the HandleFunc being returned is the modified or "wrapped" version of that function.

A typical middleware will perform some actions, then call 'next' to pass control to the subsequent middleware or the final handler, potentially perform some actions after 'next' has returned, and finally return the result of 'next'. By doing so, it forms a chain of middleware functions through which the request flows.

The Middleware type is designed to be flexible and composable, making the construction of an ordered sequence of middleware functions straightforward and modular.

Parameters:

  • 'next': The HandleFunc to wrap with additional behavior. This is the function that would normally handle the request or be the next middleware in line.

Return Value: - A HandleFunc that represents the result of adding the middleware's behavior to the 'next' function.

Usage:

  • Middleware functions are typically used with a router or a server to handle HTTP requests.
  • They are chained together so that a request goes through a series of middleware before finally being handled by the main processing function.

Example: - To write a logging middleware that logs each request:

func loggingMiddleware(next HandleFunc) HandleFunc {
    return func(w http.ResponseWriter, r *http.Request) {
        // Log the request details
        log.Printf("Request received: %s %s", r.Method, r.URL.Path)
        // Call the next middleware/handler
        next(w, r)
    }
}

// Then this middleware can be used like so:
http.Handle("/", loggingMiddleware(finalHandler))

Considerations:

  • When designing middleware, one should ensure that no necessary 'next' handlers are skipped inadvertently. Unless it's intentional (e.g., an authorization middleware stopping unauthorized requests), a middleware should usually call 'next'.
  • Be careful with error handling in middleware. Decide whether to handle and log errors within the middleware itself or pass them along to be handled by other mechanism.
  • Middleware functions should avoid altering the request unless it is part of its clear responsibility, such as setting context values or modifying headers that pertain to middleware-specific functionality.

type Server

type Server interface {
	http.Handler             // Inherited ServeHTTP method for handling requests
	Start(addr string) error // Method to start the server on a given address
	// contains filtered or unexported methods
}

Server defines the interface for an HTTP server that can handle requests and be started on a specified address. It extends the http.Handler interface of the net/http package, which requires a ServeHTTP method to serve HTTP requests. In addition to handling HTTP requests, the server can register routes with associated handlers and middleware, and be started on a network address.

Methods:

  • Start(addr string) error: Starts the server listening on the specified network address (addr). If the server fails to start, it returns an error.

  • registerRoute(method string, path string, handleFunc, mils ...Middleware): Registers a new route with a specific HTTP method and path. If provided, handleFunc becomes the main function to handle matched requests; mils represents variadic middleware functions which will be processed before the handleFunc upon route matching.

Note:

  • The registerRoute method is generally not exposed and is intended for internal use by implementations of the Server interface. Implementations should ensure that routes are properly registered and middleware is correctly applied within this method.

Example: An implementation of the Server interface could manage its own routing table and middleware stack, allowing for modular and testable server designs. It would typically be used within an application like so:

func main() {
  srv := NewMyHTTPServer()  // MyHTTPServer implements the Server interface
  srv.registerRoute("GET", "/", HomePageHandler, LoggingMiddleware)
  err := srv.Start(":8080")
  if err != nil {
    log.Fatalf("Failed to start server: %v", err)
  }
}

type StaticResourceHandler

type StaticResourceHandler struct {
	// contains filtered or unexported fields
}

StaticResourceHandler is a structure used for serving static files such as images, CSS, or JavaScript files from a defined directory within a web server. It's designed to efficiently handle requests for static content by caching frequently requested resources, understanding content types based on file extensions, and allowing limits on the size of files served.

Fields:

  • dir string: The root directory from where the static resources will be served. This should be an absolute path to ensure correct file resolution. When a request comes in for a static resource, the handler will use this directory to look up and serve the files.
  • cache *lru.Cache: An LRU (Least Recently Used) cache used to store and retrieve the most recently accessed static files quickly. The caching mechanism improves the performance of the web server by reducing the number of disk reads. The 'lru.Cache' refers to an in-memory key-value store where the key is typically the file path or name, and the value is the file's content.
  • extContentTypeMap map[string]string: A map associating file extensions with their corresponding MIME content type. This mapping allows the server to set the appropriate 'Content-Type' header in HTTP responses based on the requested file's extension. For example, it might map ".css" to "text/css" and ".png" to "image/png".
  • maxSize int: The maximum size of a file, in bytes, that the handler will serve. Requests for files larger than this size will result in an error, preventing the server from consuming excessive resources when serving large files. This is a safeguard to help maintain server performance and stability.

The StaticResourceHandler struct requires careful initialization to ensure it has access to the correct directory and that the cache and content type map are adequately configured. It can be used in standalone mode or as part of an HTTP server, integrating with the server's request handling mechanism to serve the static files when requested.

Once appropriately configured, the StaticResourceHandler provides a robust and efficient way to handle requests for static resources, enabling you to optimize the delivery of these files as part of your web application's overall performance strategy.

func InitStaticResourceHandler

func InitStaticResourceHandler(dir string, opts ...StaticResourceHandlerOption) (*StaticResourceHandler, error)

InitStaticResourceHandler initializes and returns a pointer to a StaticResourceHandler with the provided directory path and applies any given configuration options. The function also establishes an LRU (Least Recently Used) cache with a default maximum capacity to optimize the serving of static files. This function centralizes the setup logic for creating a StaticResourceHandler, ensuring that the handler is properly initialized and configured before use.

Parameters:

  • dir string: The absolute directory path where the static resources are located. This will be the root directory from which the server will serve static files.
  • opts ...StaticResourceHandlerOption: A variadic slice of functional options used to customize the configuration of the StaticResourceHandler. These options are applied in the order they're received, allowing the caller to override default values and behavior.

Return Values:

  • *StaticResourceHandler: A pointer to the newly-created configured StaticResourceHandler ready to serve static files.
  • error: An error that may have occurred during the creation or configuration of the StaticResourceHandler. If the error is not nil, it usually indicates a problem with setting up the internal LRU cache.

Internal Initialization Steps:

  1. The function creates an LRU cache with a default size of 1000 cache entries. If the cache cannot be created, the function immediately returns nil and the error.
  2. A StaticResourceHandler struct instance is instantiated with the given directory path and the newly created LRU cache.
  3. Default file size limit for serving files is set to 1 megabyte (1024 * 1024 bytes).
  4. A default extension to content type mapping is established for common file formats to ensure correct 'Content-Type' headers in HTTP responses.
  5. The function then iterates through each provided configuration option, applying it to the newly created StaticResourceHandler instance. This allows customization such as changing the maximum cache size or adding new file type mappings.
  6. The fully configured StaticResourceHandler pointer is then returned for usage in the server.

Example Usage: handler, err := InitStaticResourceHandler("/path/to/static/resources",

SetMaxSize(500 * 1024), // 500 KB as the max file size
AddFileTypeMapping("svg", "image/svg+xml"), // Add SVG MIME type mapping

)

if err != nil {
    log.Fatalf("Failed to initialize static resource handler: %v", err)
}

// Now handler can be used to serve static resources with the specified configurations.

func (*StaticResourceHandler) Handle

func (s *StaticResourceHandler) Handle(ctx *Context)

Handle takes a Context pointer and serves static files based on the request's path. It attempts to retrieve and serve the requested file, handling various error scenarios gracefully. It sets appropriate HTTP response status codes and headers, leveraging an LRU cache for performance optimization when possible.

The method logic is as follows:

  1. It extracts the requested 'file' from the context's PathValue.
  2. If there's an error in retrieving the file (e.g., malformed request path), it sends a 400 Bad Request status and a "Request path error" message.
  3. If the file can be retrieved, it constructs a full file path using the provided directory path and the file's name.
  4. The file extension is extracted to determine the correct content type from the handler's extension to MIME type mapping (extContentTypeMap).
  5. If the file's data is found in the cache, it uses this data to set the response headers and body, sending a 200 OK status code.
  6. If not cached, it reads the file from disk using os.ReadFile.
  7. If there's an error reading the file (e.g., file not found, permissions issue), it sets a 500 Internal Server Error status code and a "Server error" message.
  8. It checks if the file size is within the allowed maximum size (s.maxSize). If it is, the function adds the file's data to the cache.
  9. Lastly, it sets the correct "Content-Type" and "Content-Length" headers and sends the file data with a 200 OK status.

Parameters:

  • ctx *Context: A pointer to the Context object which contains information about the HTTP request and utilities for writing a response.

Note: This method should be used to handle routes that match static file requests. It automatically uses caching to improve performance, but it also ensures that the file size does not exceed a configured threshold before caching the data.

Example Usage: Assuming 'handler' is an instance of StaticResourceHandler with a configured directory and cache, the Handle method would be attached to a web server route like so:

http.Handle("/static/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    ctx := NewContext(r, w)
    handler.Handle(ctx)
}))

This specifies that all requests to '/static/' should be handled by the Handle method of 'handler', which will serve the files as static resources.

type StaticResourceHandlerOption

type StaticResourceHandlerOption func(handler *StaticResourceHandler)

StaticResourceHandlerOption is a type for a function which acts as an option or a modifier for instances of StaticResourceHandler. This type enables a flexible configuration pattern commonly known as "functional options", which allows the customization of various aspects of a StaticResourceHandler instance at the time of its creation or initialization.

Functional options are a way to cleanly and idiomatically pass configuration data to struct instances or objects in Go. They provide several benefits over traditional configuration approaches such as configuration structs or variadic parameters:

  1. Options are entirely optional, allowing for a more succinct API where defaults can be used unless explicitly overridden.
  2. They provide extensibility and forward-compatibility. As new options become necessary, they can be added without breaking existing clients or code.
  3. They allow for complex and interdependent properties to be set, which might be clunky or error-prone with other configuration mechanisms.
  4. They preserve the immutability of the object after creation, enabling a clearer, less error-prone API since clients are discouraged from modifying the object's properties directly after it has been created.

How StaticResourceHandlerOption is used: An option function takes a pointer to a StaticResourceHandler instance and modifies it directly. This function may set default values, modify settings, or provide additional functionality to the handler based on its implementation. During the construction or initialization of a StaticResourceHandler, one or more of these option functions can be passed, which will be applied to the handler instance to configure it according to the provided options.

Example Usage: Below is a simplified example of how one might define and use a StaticResourceHandlerOption function to configure a static resource handler for serving files from a particular directory.

func DirectoryOption(directory string) StaticResourceHandlerOption {
    return func(handler *StaticResourceHandler) {
        handler.Directory = directory
    }
}

// When creating a new StaticResourceHandler, pass the option function to configure its directory. handler := NewStaticResourceHandler(

DirectoryOption("/path/to/static/resources"),
// ...other options could be passed here as well...

)

The StaticResourceHandler can now be used with its Directory correctly set to the specified path, and this pattern permits the combination of multiple options to achieve complex configurations in an expressive and maintainable way.

func StaticWithCache

func StaticWithCache(c *lru.Cache) StaticResourceHandlerOption

StaticWithCache returns a StaticResourceHandlerOption that assigns a custom LRU (Least Recently Used) cache to a StaticResourceHandler. The provided *lru.Cache replaces the default cache, allowing for higher flexibility in how caching is configured for the static file handler. This is particularly useful for fine-tuning the cache size or sharing a cache instance among multiple handlers.

Parameters:

  • c *lru.Cache: A pointer to the lru.Cache instance that should be used by the StaticResourceHandler. This parameter allows the user to specify the exact cache instance, including its size and eviction policies, which will be integrated into the static resource serving process.

Returns:

  • StaticResourceHandlerOption: A closure function that accepts a *StaticResourceHandler as its parameter. When executed, this option function sets the StaticResourceHandler's internal cache pointer to the provided *lru.Cache instance.

This configuration option is valuable when performance optimization is needed or when different caching strategies are tested. It provides the ability to swap in a custom cache with a pre-defined configuration without altering the existing flow of the handler's initialization.

Example Usage: To use a previously configured lru.Cache with a capacity of 500 items in a new StaticResourceHandler, invoke StaticWithCache like this:

existingCache, _ := lru.New(500) // Create an lru.Cache with a capacity for 500 items. handler, err := InitStaticResourceHandler("/static", StaticWithCache(existingCache))

if err != nil {
    // handle error
}

This allows the new StaticResourceHandler to utilize the existingCache for caching static files, providing a customized caching strategy as per the application's requirements.

Adopting a feature-rich cache can significantly reduce IO operations against the disk and improve the serving speed of static files, leading to better application performance and scalability. The option to set a custom cache is a direct way to control these aspects.

func StaticWithExtension

func StaticWithExtension(extMap map[string]string) StaticResourceHandlerOption

StaticWithExtension returns a StaticResourceHandlerOption which extends or overrides the existing file extension to MIME type mappings in a StaticResourceHandler. The provided extMap parameter is a map of file extensions to their respective MIME types. This function is helpful when you need the StaticResourceHandler to recognize additional file types or modify existing associations.

Parameters:

  • extMap map[string]string: This map represents the file extensions and their associated MIME types that should be recognized by the StaticResourceHandler. Keys in the map should be file extensions without the dot (e.g., "txt"), and the values should be the corresponding MIME types (e.g., "text/plain").

Returns:

  • StaticResourceHandlerOption: A functional option that, when applied to a StaticResourceHandler, updates its 'extContentTypeMap' field to include the mappings from extMap. If an extension already exists in the handler's mapping, it will be overridden with the new MIME type provided in extMap.

This function offers a way to customize the content type determination process when serving static files. By specifying file extension to MIME type mappings, the server can set correct 'Content-Type' headers in HTTP responses. This is vital for browsers or clients to handle the received files appropriately.

Example Usage: To add or override mappings for ".svg" and ".json" files in a StaticResourceHandler, use StaticWithExtension like this:

customExtMap := map[string]string{
    "svg": "image/svg+xml",
    "json": "application/json",
}

handler, err := InitStaticResourceHandler("/static", StaticWithExtension(customExtMap))

if err != nil {
    // handle error
}

The above code configures the handler to recognize ".svg" files with the MIME type "image/svg+xml" and ".json" files with "application/json". These mappings will be added to or replace any existing mappings for these extensions in the handler.

This level of customization aids in serving a broader range of file types or catering to specific client needs while ensuring that the server's responses are correctly understood by the client.

func StaticWithMaxFileSize

func StaticWithMaxFileSize(maxSize int) StaticResourceHandlerOption

StaticWithMaxFileSize returns a StaticResourceHandlerOption which sets the maximum file size (in bytes) that a StaticResourceHandler is allowed to serve. The maxSize parameter specifies the size limit, and files exceeding this limit will not be served by the handler. This option function is part of a pattern allowing granular configuration of a StaticResourceHandler through functional options, which are applied when initializing the handler with the InitStaticResourceHandler function.

Parameters:

  • maxSize int: The maximum size (in bytes) that the StaticResourceHandler will serve. This acts as a guard against serving excessively large static files, potentially consuming too much memory or bandwidth.

Returns:

  • StaticResourceHandlerOption: A function closure that when called with a *StaticResourceHandler, will assign the specified maxSize to the handler's maxSize field.

The maxSize is an essential configuration as it helps to manage server resources efficiently and ensures the server does not get overloaded by requests for very large files. This is particularly useful when you expect that your server might be serving large files and wish to put an explicit cap on them.

Example Usage: To create a StaticResourceHandler that has a maximum serving file size of 500KB, you would use the StaticWithMaxFileSize option like so:

handler, err := InitStaticResourceHandler("/static", StaticWithMaxFileSize(500 * 1024))

if err != nil {
    // handle error
}

When the above handler is used in a server, any request for a static file larger than 500KB will be denied or handled according to the server's implementation.

Using this function enables the developer to tailor the StaticResourceHandler's behavior to the specific requirements of their application or the resource constraints of their server environment.

type StringValue

type StringValue struct {
	// contains filtered or unexported fields
}

StringValue is a structure designed to encapsulate a string value and any associated error that may arise during the retrieval of the value. It is commonly used in functions that perform operations which may fail, such as parsing, reading from a file, or extracting values from a request in web applications. By combining both the value and the error in a single struct, it simplifies error handling and value passing between functions.

Fields:

  • 'val': This field holds the string value that is retrieved by the operation. For example, when extracting a value from a form or parsing a string, 'val' will hold the result. If the operation to retrieve the value fails (for instance, if a key doesn't exist or a parse error occurs), 'val' will typically be set to an empty string.

  • 'err': This field is used to hold any error that occurred during the operation. The presence of a non-nil error typically indicates that something went wrong during the value retrieval process. It allows the caller to distinguish between a successful operation (where 'err' is nil) and unsuccessful ones (where 'err' is not nil). The specific error stored in 'err' can provide additional context about what went wrong, enabling the caller to take appropriate actions, such as logging the error or returning an error response in a web application.

Usage:

  • The 'StringValue' struct is useful in scenarios where a function needs to return both a value and an error status, so the caller can easily handle errors and control flow. It is particularly helpful in HTTP handler functions where error handling is integral to the proper functioning of the server.

Example:

  • Suppose there is a web server with a function that reads a configuration value labeled "timeout" from a file or an environment variable. If the retrieval is successful, 'val' will contain the timeout string, and 'err' will be nil. If the retrieval fails (for example, if the "timeout" label doesn't exist), then 'err' will contain the error message, and 'val' will be an empty string. This struct helps the caller response appropriately based on whether an error occurred or not.

Considerations:

  • When using 'StringValue' in code, it is good practice to always check the 'err' field before using the 'val' field. This avoids any surprises from using invalid values.
  • The design of 'StringValue' is such that it obviates the need for functions to return separate values for the string retrieved and an error. Instead, both pieces of information can be returned together in a more streamlined manner.

func (*StringValue) AsFloat64

func (s *StringValue) AsFloat64() (float64, error)

AsFloat64 converts the string value encapsulated within the StringValue struct to a float64 type. This operation is essential in situations where the string value is expected to contain a floating-point number that will be used in complex calculations or any context where precise decimal values are necessary, such as financial computations or scientific measurements.

The method follows a clear two-step conversion process:

  1. It first checks for the presence of an error in the 'err' field of the StringValue struct. If an error is already associated with the value, the method precludes any conversion attempt and immediately returns a zero value (0.0) and the stored error, preserving the integrity of the error handling flow.

  2. If no error is found (i.e., 'err' is nil), the method utilizes the strconv.ParseFloat function to attempt the conversion of the string value to a float64. The function parameter '64' specifies that the conversion should result in a floating-point number that adheres to a 64-bit IEEE 754 representation. This conversion is capable of handling both integer values and floating-point strings, including those with scientific notation.

    If the conversion is conducted successfully, the parsed float64 value is returned alongside a nil error to indicate a successful operation. However, if strconv.ParseFloat encounters any issues—such as if the string contains characters inappropriate for a numeric value, or if the number is outside the range representable by a float64—the method will instead yield a zero value (0.0) with the corresponding error.

Parameters: - None. The method operates solely on the fields contained within the invoked StringValue struct instance.

Return Values: - A float64 value representing the successfully converted string or 0.0 in the event of an error. - An error object that either carries an existing error from 'err' or a newly encountered error in conversion.

Usage:

  • Users of this method should handle the returned error prior to using the numeric result to ensure that no conversion error has taken place and the result is indeed a valid and accurate floating-point number.

Example: - If a 'StringValue' instance named 'priceString' comes from a reliable function that parses a price value:

priceString := parsePriceValueFromInput()
price, err := priceString.AsFloat64()
if err != nil {
    // Error handling logic such as logging the error or prompting the user to provide a valid numeric value.
} else {
    // The price variable is now appropriately typed as a float64 and ready for financial calculations.
}

Considerations:

  • The float64 type follows IEEE 754 standards and is the set choice for all floating-point operations within Go, offering a double-precision floating-point format which is fairly suited for a wide range of numerical tasks.
  • Ensure that the source string is supposed to represent a floating-point value and that it is formatted correctly. Proper validation or sanitization might be essential if the input is obtained from external or untrusted sources.

func (*StringValue) AsInt64

func (s *StringValue) AsInt64() (int64, error)

AsInt64 attempts to convert the value held in the StringValue struct to an int64 type. This method is particularly useful when the string value is expected to hold a numeric value that needs to be used in a context where integer types are required (e.g., calculations, database operations, etc.).

This method performs a two-step process:

  1. It checks if the err field of the StringValue receiver is not nil, which implies that an error occurred in acquiring or processing the original string value. If an error is present, the method immediately returns 0 and the error, propagating the original error without attempting to convert the value.
  2. If there is no error associated with the string value (i.e., err is nil), the method attempts to parse the string as an int64 base 10 number with the strconv.ParseInt function. If the parsing succeeds, it returns the resulting int64 value and a nil error. If parsing fails, it returns 0 and the parsing error that occurred.

Parameters: - None. The method operates on the StringValue structs internal state.

Return Value:

  • The first return value is the int64 result of the parsing operation. It is set to 0 if there is an error.
  • The second return value is the error encountered during the conversion process. It will contain any error that may have previously been present in the StringValue struct or any error that occurs during the parsing with strconv.ParseInt.

Usage:

  • It is essential to always handle the error return value to ensure that the int64 conversion was successful. Do not use the numeric value if the error is non-nil, as it would be incorrect or undefined.

Example:

  • Suppose we have a StringValue struct that is created as the result of another function that reads a stringifies integer from user input or external data source:

    value := otherFunctionThatReturnsStringValue() number, err := value.AsInt64() if err != nil { // handle the error (e.g., log the error or inform the user of a bad input) } else { // use the number for further processing }

Considerations:

  • This method allows for a clean and efficient interpretation of string data when an integer is expected. Doing so can simplify error handling by centralizing the conversion logic and error checking.
  • The strconv.ParseInt function is configured to interpret the string as a base 10 integer within the int64 range. This corresponds to the range of -9223372036854775808 to 9223372036854775807.
  • Make sure that the source string is appropriately validated or sanitized if coming from an untrusted source before attempting the conversion to mitigate any risks such as injection attacks or data corruption.

func (*StringValue) AsUint64

func (s *StringValue) AsUint64() (uint64, error)

AsUint64 attempts to convert the string value within the StringValue struct to an uint64 type. This method is crucial when the string is expected to represent an unsigned numeric value that must be processed in environments or calculations that specifically require unsigned integers.

The method involves the following steps:

  1. First, it verifies whether the 'err' field in the StringValue struct is not nil, indicating an error was encountered during the prior retrieval or conversion of the string value. Should an error be present, the method exits early, returning 0 for the numeric value and passing the error forward.
  2. If the 'err' field is nil, signaling no previous error, the method proceeds to parse the string value to an uint64 using the strconv.ParseUint function. This function is instructed to interpret the string value as a base 10 number. The second argument (10) specifies the number base (decimal in this case), and the third argument (64) specifies that the conversion should fit into a 64-bit unsigned integer format.
  3. If the conversion is successful, the method outputs the parsed uint64 value and a nil error. If the conversion fails (e.g., if the string contains non-numeric characters or represents a number outside the uint64 range), it instead returns 0 and the error produced by strconv.ParseUint.

Parameters: - There are no parameters taken by this method, as it operates on the 'StringValue' struct instance it is called upon.

Return Value: - An uint64 type value representing the converted string if successful. - An error indicating the conversion failed or an error was present already in the StringValue struct's 'err' field.

Usage:

  • The caller should always evaluate the error returned by this function before utilizing the numeric value, to ensure the conversion occurred correctly and the result is valid and reliable for further use.

Example: - Imagine a situation where the 'StringValue' instance 'numericString' was created by parsing a user-provided configuration value:

numericString := GetStringFromConfig("max_users")
maxValue, err := numericString.AsUint64()
if err != nil {
    // Handle the error appropriately (e.g., fallback to default value, logging, or user notification)
} else {
    // The maxValue is now safe to use for setting the maximum users allowed
}

Considerations:

  • This method assists in preventing the proliferation of error handling logic scattered throughout codebases by encapsulating both the value and potential errors within a single, self-contained struct.
  • The uint64 data type can represent integers from 0 to 18,446,744,073,709,551,615. Ensure the source string is meant to fit within this range.
  • Additional validation might be required for the initial string value if it comes from external or user inputs to prevent errors during conversion.

type TemplateEngine

type TemplateEngine interface {
	// Render takes the name of a template and the data object to be used in rendering, and returns the
	// rendered template as a slice of bytes, or an error if the rendering could not be completed. This
	// method abstracts the rendering logic, enabling different templating systems to be integrated into
	// the application as needed.
	Render(ctx context.Context, templateName string, data any) ([]byte, error)
}

TemplateEngine defines the contract for a template rendering system used to generate text output (such as HTML, XML, etc.) based on predefined templates and dynamic data. Such an engine typically supports a variety of operations related to template parsing, data binding, and the generation of rendered output. This interface abstracts these operations so that different implementations of templating engines can be used interchangeably within an application.

The interface includes a single method, Render, which must be implemented by any concrete type that purports to be a template engine. This method takes a template name and associated data and produces the rendered output as a slice of bytes, along with an error if the rendering process fails.

Render method parameters:

  • ctx (context.Context): The context parameter allows the Render method to be aware of the broader context of the application, such as deadlines, cancellation signals, and other request-scoped values. It enables the rendering process to handle timeouts or cancellations as per the application's context.
  • templateName (string): This is the identifier or the name of the template that needs to be rendered. The templating engine uses this name to look up and load the appropriate template file or content from an internal cache or the filesystem.
  • data (any): The data parameter is an interface{} type, allowing any kind of Go value to be passed as the data context for the template. This data is then utilized by the template engine to dynamically populate placeholders within the template, enabling the generation of customized output based on the data provided.

Render method returns:

  • []byte: When successful, Render returns the generated content as a byte slice, which can be used directly as output to a response writer or converted to a string for further processing.
  • error: If any errors occur during the rendering of the template, Render returns an error detailing the issue encountered. This could be due to reasons like template parsing errors, missing data required to fill in the template, file system issues when accessing template files, etc.

Notes:

  • Implementations of the TemplateEngine interface should ensure to handle any template-specific syntax and errors internally, providing a consistent and easy-to-use API for rendering content within an application.
  • The flexibility of this interface allows for custom implementations that could include enhanced features like caching, internationalization support, and more.

Directories

Path Synopsis
internal
middlewares

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL