Reputation: 949
Ok so I am Go Lang with the Echo framework, to try and build pdf which will load data from a database source - that bit will come later.
So this is how I am rendering my pdf html
layout,
func (c *Controller) DataTest(ec echo.Context) error {
return ec.Render(http.StatusOK, "pdf.html", map[string]interface{}{
"name": "TEST",
"msg": "Hello, XXXX!",
})
}
The above function works fine, and renders the html (I built a temp path to the function). Now I want to use that function as my html template to build my pdf's.
So I am using wkhtmltopdf
and the lib "github.com/SebastiaanKlippert/go-wkhtmltopdf"
This is how I would render the html in the pdf,
html, err := ioutil.ReadFile("./assets/pdf.html")
if err != nil {
return err
}
But I need to be able to update the template so that is why I am trying to render the page and take that into the pdf.
However, the Echo framework returns an error type and not of type bytes or strings and I am not sure how to update it so my rendered content is returned as bytes?
Thanks,
UPDATE
page := wkhtmltopdf.NewPageReader(bytes.NewReader(c.DataTest(data)))
This is how I am currently doing, the data is just a html string which is then turned into a slice of bytes for the NewReader
.
This works fine, but I wanted to turn the DataTest
function into a fully rendered html page by Echo. The problem with that is that when you return a rendered page, it is returned as an error type.
So I was trying to work out a why of updating it, so I could return the data as an html string, which would then be put in as a slice of bytes.
Upvotes: 2
Views: 4259
Reputation: 1610
if you want rendered html, use echo' custom middleware. I hope it helps you.
main.go
package main
import (
"bufio"
"bytes"
"errors"
"fmt"
"html/template"
"io"
"net"
"net/http"
"github.com/labstack/echo"
)
type TemplateRegistry struct {
templates map[string]*template.Template
}
func (t *TemplateRegistry) Render(w io.Writer, name string, data interface{}, c echo.Context) error {
tmpl, ok := t.templates[name]
if !ok {
err := errors.New("Template not found -> " + name)
return err
}
return tmpl.ExecuteTemplate(w, "base.html", data)
}
func main() {
e := echo.New()
templates := make(map[string]*template.Template)
templates["about.html"] = template.Must(template.ParseFiles("view/about.html", "view/base.html"))
e.Renderer = &TemplateRegistry{
templates: templates,
}
// add custom middleware
// e.Use(PdfMiddleware)
// only AboutHandler for Pdf
e.GET("/about", PdfMiddleware(AboutHandler))
// Start the Echo server
e.Logger.Fatal(e.Start(":8080"))
}
// custom middleware
func PdfMiddleware(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) (err error) {
resBody := new(bytes.Buffer)
mw := io.MultiWriter(c.Response().Writer, resBody)
writer := &bodyDumpResponseWriter{Writer: mw, ResponseWriter: c.Response().Writer}
c.Response().Writer = writer
if err = next(c); err != nil {
c.Error(err)
}
// or use resBody.Bytes()
fmt.Println(resBody.String())
return
}
}
type bodyDumpResponseWriter struct {
io.Writer
http.ResponseWriter
}
func (w *bodyDumpResponseWriter) WriteHeader(code int) {
w.ResponseWriter.WriteHeader(code)
}
func (w *bodyDumpResponseWriter) Write(b []byte) (int, error) {
return w.Writer.Write(b)
}
func (w *bodyDumpResponseWriter) Flush() {
w.ResponseWriter.(http.Flusher).Flush()
}
func (w *bodyDumpResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
return w.ResponseWriter.(http.Hijacker).Hijack()
}
func AboutHandler(c echo.Context) error {
return c.Render(http.StatusOK, "about.html", map[string]interface{}{
"name": "About",
"msg": "All about Boatswain!",
})
}
view/about.html
{{define "title"}}
Boatswain Blog | {{index . "name"}}
{{end}}
{{define "body"}}
<h1>{{index . "msg"}}</h1>
<h2>This is the about page.</h2>
{{end}}
view/base.html
{{define "base.html"}}
<!DOCTYPE html>
<html>
<head>
<title>{{template "title" .}}</title>
</head>
<body>
{{template "body" .}}
</body>
</html>
{{end}}
Upvotes: 1
Reputation: 2272
So from what I understand you want to:
So, the reason Echo returns error
is because it actually not only does the template rendering, but also sending a response to client. If you want to do something else in-between, you can't use that method from echo.
Luckily, echo doesn't do anything magical there. You can just use the standard template package with the same result.
func GetHtml(filename string, data interface{}) (string, error) {
filedata, err := ioutil.ReadFile(filename)
if err != nil {
return "", err
}
asString := string(filedata)
t, err := template.New("any-name").Parse(asString)
if err != nil {
return "", err
}
var buffer bytes.Buffer
err = t.Execute(&buffer, data)
if err != nil {
return "", err
}
return buffer.String(), nil
}
There you have your function that returns a string
. You can use buffer.Bytes()
to have a byte array if that's preferrable.
After this you can do whatever you need to, like convert to PDF and write it back to clients using echoCtx.Response().Writer()
.
Hope that helps, but in future try asking more precise questions, then you are more likely to receive an accurate response.
Upvotes: 0