Skip to content

Commit

Permalink
Merge pull request #14 from go-labx/feature/support-template
Browse files Browse the repository at this point in the history
feat: support template engine and static file hosting
  • Loading branch information
kk0829 authored May 14, 2023
2 parents 086fc55 + 2da7aad commit 4cec741
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 3 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## [0.5.0] - May 14, 2023

### Added

- `ctx.HTML(code int, name string, data interface{})` writes an HTML response with the given status code, template name, and data.
- `ctx.Static(root string, prefix string)` serves static files from the given root directory with the given prefix.
- `app.LoadHTMLGlob(pattern string)` loads HTML templates from a glob pattern and sets them in the Application struct.
- `app.SetFuncMap(funcMap template.FuncMap)` sets the funcMap in the Application struct to the funcMap passed in as an argument.

## [0.4.1] - May 13, 2023

### Changed
Expand Down
1 change: 1 addition & 0 deletions consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package lightning
// MIME types
const (
MIMETextPlain = "text/plain"
MIMETextHTML = "text/html"
MIMEApplicationXML = "application/xml"
MIMEApplicationJSON = "application/json"
)
Expand Down
12 changes: 12 additions & 0 deletions context.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,18 @@ func (c *Context) Text(code int, text string) {
c.res.setBody([]byte(text))
}

// HTML writes an HTML response with the given status code, template name, and data.
func (c *Context) HTML(code int, name string, data interface{}) {
c.SetHeader(HeaderContentType, MIMETextHTML)
c.SetStatus(code)

if err := c.App.htmlTemplates.ExecuteTemplate(c.Res, name, data); err != nil {
c.Text(500, err.Error())
} else {
c.SkipFlush()
}
}

// XML writes an XML response with the given status code and object.
func (c *Context) XML(code int, obj interface{}) {
encodeData, err := xml.Marshal(obj)
Expand Down
35 changes: 35 additions & 0 deletions examples/static/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package main

import (
"fmt"
"github.com/go-labx/lightning"
"html/template"
"time"
)

func formatDate(t time.Time) string {
year, month, day := t.Date()
return fmt.Sprintf("%d-%02d-%02d", year, month, day)
}

func main() {
// Create a new Lightning app
app := lightning.DefaultApp()

app.Static("./public", "/static")
app.SetFuncMap(template.FuncMap{
"formatDate": formatDate,
})
app.LoadHTMLGlob("templates/*")

app.Get("/", func(ctx *lightning.Context) {
ctx.HTML(200, "index.tmpl", lightning.Map{
"title": "Lightning",
"description": "Lightning is a lightweight and fast web framework for Go. It is designed to be easy to use and highly performant. ⚡️⚡️⚡️",
"now": time.Now(),
})
})

// Run the app
app.Run()
}
3 changes: 3 additions & 0 deletions examples/static/public/css/1.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
body {
background-color: cyan;
}
1 change: 1 addition & 0 deletions examples/static/public/js/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("hello world")
16 changes: 16 additions & 0 deletions examples/static/templates/index.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="/static/css/1.css" />
<script src="/static/js/1.js"></script>
</head>
<body>
<h2>{{.title}}</h2>
<p>{{.description}}</p>
<p>{{.now | formatDate }}</p>
</body>
</html>
50 changes: 47 additions & 3 deletions lightning.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ package lightning
import (
"encoding/json"
"net/http"
"os"
"path"
"path/filepath"
"reflect"
"strings"
"text/template"

"github.com/go-labx/lightlog"
)
Expand All @@ -16,9 +21,11 @@ type Middleware = HandlerFunc
type Map map[string]any

type Application struct {
Config *Config
router *router
middlewares []HandlerFunc
Config *Config
router *router
middlewares []HandlerFunc
htmlTemplates *template.Template
funcMap template.FuncMap

Logger *lightlog.ConsoleLogger
}
Expand Down Expand Up @@ -153,6 +160,43 @@ func (app *Application) Group(prefix string) *Group {
return newGroup(app, prefix)
}

// Static serves static files from the given root directory with the given prefix.
// It uses the os.Executable function to get the path of the executable file,
// and then joins it with the root and the path after the prefix to get the full file path.
// If the file exists, it is served with a 200 status code using the http.ServeFile function.
// If the file does not exist, a 404 status code is returned with the text "Not Found".
func (app *Application) Static(root string, prefix string) {
ex, err := os.Executable()
if err != nil {
panic(err)
}
exPath := filepath.Dir(ex)

app.Get(path.Join(prefix, "/*"), func(ctx *Context) {
fullFilePath := filepath.Join(exPath, root, strings.TrimPrefix(ctx.Path, prefix))

if _, err := os.Stat(fullFilePath); !os.IsNotExist(err) {
ctx.SkipFlush()
ctx.SetStatus(http.StatusOK)
http.ServeFile(ctx.Res, ctx.Req, fullFilePath)
} else {
ctx.Text(http.StatusNotFound, http.StatusText(http.StatusNotFound))
}
})
}

// SetFuncMap sets the funcMap in the Application struct to the funcMap passed in as an argument.
func (app *Application) SetFuncMap(funcMap template.FuncMap) {
app.funcMap = funcMap
}

// LoadHTMLGlob loads HTML templates from a glob pattern and sets them in the Application struct.
// It uses the template.Must function to panic if there is an error parsing the templates.
// It also sets the funcMap in the Application struct to the funcMap passed in as an argument.
func (app *Application) LoadHTMLGlob(pattern string) {
app.htmlTemplates = template.Must(template.New("").Funcs(app.funcMap).ParseGlob(pattern))
}

// ServeHTTP is the function that handles HTTP requests.
// It finds the matching route, creates a new Context, sets the route parameters,
// and executes the MiddlewareFunc chain.
Expand Down

0 comments on commit 4cec741

Please sign in to comment.