Code Monkey home page Code Monkey logo

toolbox's Introduction

Version Built with GoLang License Go Report Card Tests Go Coverage

Toolbox

A simple example of how to create a reusable Go module with commonly used tools.

The included tools are:

  • Read JSON
  • Write JSON
  • Produce a JSON encoded error response
  • Write XML
  • Read XML
  • Produce an XML encoded error response
  • Upload a file to a specified directory
  • Download a static file
  • Get a random string of length n
  • Post JSON to a remote service
  • Create a directory, including all parent directories, if it does not already exist
  • Create a URL safe slug from a string

Installation

go get -u github.com/tsawler/toolbox

Usage

package main

import (
	"fmt"
	"github.com/tsawler/toolbox"
)

func main() {
	// create a variable of type toolbox.Tools, so we can use this variable
	// to call the methods on that type
	var tools toolbox.Tools

	// get a random string
	rnd := tools.RandomString(10)
	fmt.Println(rnd)
}

Working with JSON

In a handler, for example:

// JSONPayload is the type for JSON data that we receive
type JSONPayload struct {
    Name string `json:"name"`
    Data string `json:"data"`
}

// SomeHandler is the handler to accept a post request consisting of json payload
func (app *Config) SomeHandler(w http.ResponseWriter, r *http.Request) {
    var tools toolbox.Tools
    
    // read json into var
    var requestPayload JSONPayload
    _ = tools.ReadJSON(w, r, &requestPayload)
	
    // do something with the data here...
    
    // create the response we'll send back as JSON
    resp := toolbox.JSONResponse{
        Error:   false,
        Message: "logged",
    }
    
    // write the response back as JSON
    _ = tools.WriteJSON(w, http.StatusAccepted, resp)
}

Download a file

To download a static file, and force it to download instead of displaying in a browser:

// DownloadAFile downloads an arbitrary file
func (app *Config) DownloadAFile(w http.ResponseWriter, r *http.Request) {
    var tools toolbox.Tools

    tools.DownloadStaticFile(w, r, "./data", "file.pdf", "file.pdf")
}

Creating a directory

To create a directory if it does not already exist:

// SomeHandler is some kind of handler
func (app *Config) SomeHandler(w http.ResponseWriter, r *http.Request) {
    var tools toolbox.Tools

    err := tools.CreateDirIfNotExist("./myDir")
    if err != nil {
        // do something with the error...
    }
	
    // keep going in the handler...
}

Uploading a File:

To upload a file to a specific directory, with this for HTML:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
    <title>Upload test</title>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col">
            <h1 class="mt-2">Upload a file</h1>
            <hr>

            <form action="http://localhost:8080/upload" method="post" enctype="multipart/form-data">

                <div class="mb-3">
                    <label for="fileUpload" class="form-label">Choose file(s) to upload...</label>
                    <input class="form-control" type="file" id="fileUpload" name="uploaded" multiple>
                </div>


                <input class="btn btn-primary" type="submit" value="Upload file">
            </form>

        </div>
    </div>
</div>
</body>
</html>

And this for a Go application:

package main

import (
	"fmt"
	"github.com/tsawler/toolbox"
	"log"
	"net/http"
)

func main() {

	// handle html route (http://localhost:8080/)
	http.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("."))))

	// Post handler 
	http.HandleFunc("/upload", func(w http.ResponseWriter, r *http.Request) {
		if r.Method != "POST" {
			http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
			return
		}

		t := toolbox.Tools{
			MaxFileSize:      1024 * 1024 * 1024,
			AllowedFileTypes: []string{"image/gif", "image/png", "image/jpeg"},
		}
		

		// Upload the file(s). Note that if you don't want the files to be renamed,
		// you can add an optional final parameter -- true will rename the files (the default)
		// and false will preserve the original filenames, for example:
		// files, err := t.UploadFiles(r, "./uploads", false)
		// n.b.: if the "./uploads" directory does not exist, we attempt to create it.
		files, err := t.UploadFiles(r, "./uploads")
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		// the returned variable, files, will be a slice of the type toolbox.UploadedFile
		_, _ = w.Write([]byte(fmt.Sprintf("Uploaded %d file(s) to the uploads folder", len(files))))	
	})

	// print a log message
	log.Println("Starting server on port 8080")

	// start the server
	http.ListenAndServe(":8080", nil)
}

Calling a Remote API

To make a JSON post to a remote URI, with this html:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"
          integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
          crossorigin="anonymous">

    <title>JSON functionality</title>
    <style>
        label{
            font-weight: bold;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col">
            <h1 class="mt-2">JSON functionality</h1>
            <hr>

            <form>


                <div class="mb-3">
                    <label for="json" class="form-label">JSON to Send:</label>
                    <textarea style="font-family: Courier,sans-serif" class="form-control"
                              id="json" name="json" rows="5">
{
    "action": "some action",
    "message": "some message"
}
                    </textarea>
                </div>


                <a id="pushBtn" class="btn btn-primary">Push JSON</a>
            </form>
            <hr>
            <p><strong>Response from server:</strong></p>
            <div style="outline: 1px solid silver; padding: 2em">
                <pre id="response">No response from server yet...</pre>
            </div>

        </div>
    </div>
</div>

<script>
    let pushBtn = document.getElementById("pushBtn");
    let jsonPayload = document.getElementById("json")
    let serverResponse = document.getElementById("response");

    pushBtn.addEventListener("click", function () {
        const payload = jsonPayload.value;
        const headers = new Headers();

        const body = {
            method: 'POST',
            body: payload,
            headers: headers,
        }

        headers.append("Content-Type", "application/json");

        fetch("http://localhost:8081/receive-post", body)
            .then((response) => response.json())
            .then((data) => {
                serverResponse.innerHTML = JSON.stringify(data, undefined, 4);
            })
            .catch((error) => {
                serverResponse.innerHTML = "<br><br>Error: " + error;
            })
    })
</script>
</body>
</html>

You can use this kind of Go code:

package main

import (
	"github.com/tsawler/toolbox"
	"log"
	"net/http"
)

func main() {
	// create a default server mux
	mux := http.NewServeMux()

	// register routes
	mux.Handle("/", http.StripPrefix("/", http.FileServer(http.Dir("."))))
	mux.HandleFunc("/receive-post", receivePost)
	mux.HandleFunc("/remote-service", remoteService)

	// print a log message
	log.Println("Starting server on port 8081")

	// start the server
	err := http.ListenAndServe(":8081", mux)
	if err != nil {
		log.Fatal(err)
	}
}

// RequestPayload describes the JSON that this service accepts as an HTTP Post request
type RequestPayload struct {
	Action  string `json:"action"`
	Message string `json:"message"`
}

// ResponsePayload is the structure used for sending a JSON response
type ResponsePayload struct {
	Message    string `json:"message"`
	StatusCode int    `json:"status_code,omitempty"`
}

func receivePost(w http.ResponseWriter, r *http.Request) {
	// get the posted json and decode it
	var requestPayload RequestPayload
	var t toolbox.Tools

	err := t.ReadJSON(w, r, &requestPayload)
	if err != nil {
		_ = t.ErrorJSON(w, err)
		return
	}

	// Call remote service. Note that we are ignoring the first return parameter, which is the 
	// entire response from the remote service, but you have access to it if you need it.
	_, statusCode, err := t.PushJSONToRemote("http://localhost:8081/remote-service", requestPayload)
	if err != nil {
		_ = t.ErrorJSON(w, err)
		return
	}

	// send response
	payload := ResponsePayload{
		Message:    "hit the service ok",
		StatusCode: statusCode,
	}

	err = t.WriteJSON(w, http.StatusAccepted, payload)
	if err != nil {
		log.Println(err)
	}
}

// remoteService just simulates calling some remote API
func remoteService(w http.ResponseWriter, r *http.Request) {
	payload := ResponsePayload{
		Message: "OK",
	}
	var t toolbox.Tools

	_ = t.WriteJSON(w, http.StatusOK, payload)
}

Create a slug from a string

To slugify a string, we simply remove all non URL safe characters and return the original string with a hyphen where spaces would be. Example:

package main

import (
	"fmt"
	"github.com/tsawler/toolbox"
)

func main() {
	toSlugify := "hello, world! These are unsafe chars: こんにちは世界*!&^%"
	fmt.Println("To slugify:", toSlugify)
	var tools toolbox.Tools

	slug, err := tools.Slugify(toSlugify)
	if err != nil {
		fmt.Println(err)
	}

	fmt.Println("Slugified:", slug)
}

Output from this is:

To slugify: hello, world! These are unsafe chars: こんにちは世界*!&^%
Slugified: hello-world-these-are-unsafe-chars

toolbox's People

Contributors

tsawler avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.