Go
A Go program that uses the API with the standard library only: net/http and encoding/json. It lists a template's labelled variables, measures the drawing it makes with the values given, and exports it as a PDF.
Download it: main.go.
// main.go: list a template's inputs, measure it and export it as a PDF with the PiQ SaaS API.
// Go 1.18 or later; the standard library only.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"strings"
)
const template = "L=400,\"Length\"\nW=300,\"Width\"\nP1=[L,0]\nP2=[L,W]\nP3=[0,W]\nPOLYLINE @1,[P0,P1,P2,P3],TRUE,0"
var key, base = os.Getenv("PIQ_API_KEY"), strings.TrimSuffix(os.Getenv("PIQ_URL"), "/")
// Request is the JSON body of a request: a template (or its source), values and, to save, where to.
type Request struct {
Template string `json:"template,omitempty"`
Source *Object `json:"source,omitempty"`
Values map[string]any `json:"values,omitempty"`
Destination *Object `json:"destination,omitempty"`
Overwrite bool `json:"overwrite,omitempty"`
}
// Object is an object in one of your registered storages.
type Object struct {
Storage string `json:"storage"`
Key string `json:"key"`
}
func post(path string, body Request) *http.Response {
data, _ := json.Marshal(body)
req, _ := http.NewRequest("POST", base+path, bytes.NewReader(data))
req.Header.Set("X-API-KEY", key)
req.Header.Set("Content-Type", "application/json")
response, err := http.DefaultClient.Do(req)
if err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
if response.StatusCode >= 300 {
fmt.Fprintln(os.Stderr, "Error", response.Status)
var problem struct {
Title, Detail string
Errors map[string][]string
}
text, _ := io.ReadAll(response.Body) // a 401 has no body
if len(text) > 0 && json.Unmarshal(text, &problem) != nil {
problem.Detail = string(text)
}
for _, line := range []string{problem.Title, problem.Detail} {
if line != "" {
fmt.Fprintln(os.Stderr, line)
}
}
for field, messages := range problem.Errors {
fmt.Fprintf(os.Stderr, " %s: %s\n", field, strings.Join(messages, " "))
}
os.Exit(1)
}
return response
}
func postFor(path string, body Request, result any) {
response := post(path, body)
defer response.Body.Close()
json.NewDecoder(response.Body).Decode(result)
}
func main() {
if key == "" {
fmt.Fprintln(os.Stderr, "Set PIQ_API_KEY to your API key.")
os.Exit(1)
}
if base == "" {
base = "https://saas.parametriq.co.uk"
}
storage := os.Getenv("PIQ_STORAGE") // optional: a registered storage's name
// the template itself, or (optional) where it is kept in your storage
request := Request{Template: template}
if storage != "" {
request = Request{Source: &Object{storage, "templates/box.piq"}}
}
// 1. The template's labelled variables
var inputs struct {
Inputs []struct {
Name, Label, Kind string
Value any
}
}
postFor("/inputs", request, &inputs)
for _, i := range inputs.Inputs {
fmt.Printf("%s: %s (%s, %v)\n", i.Name, i.Label, i.Kind, i.Value)
}
// 2. The drawing measured, with the values given
var m struct {
Width, Height float64
Layers []struct {
Layer string
Length float64
}
}
request.Values = map[string]any{"L": 500, "W": 250}
postFor("/measure", request, &m)
cut := 0.0
for _, layer := range m.Layers {
if layer.Layer == "Cut" {
cut = layer.Length
}
}
fmt.Printf("Size: %v x %v, cut length: %v\n", m.Width, m.Height, cut)
// 3. The drawing as a PDF
pdf := post("/export/pdf", request)
data, _ := io.ReadAll(pdf.Body)
if err := os.WriteFile("box.pdf", data, 0o644); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
fmt.Printf("Saved box.pdf (%s warnings)\n", pdf.Header.Get("X-PiQ-Warnings"))
// 4. Optional: the PDF saved to your storage instead of downloaded
if storage != "" {
request.Destination, request.Overwrite = &Object{storage, "drawings/box.pdf"}, true
var saved struct {
Storage, Key string
Size int64
}
postFor("/save/pdf", request, &saved)
fmt.Printf("Saved %s to %s (%d bytes)\n", saved.Key, saved.Storage, saved.Size)
}
}
How it works
- Settings. The key comes from
PIQ_API_KEY, the address fromPIQ_URL(the service itself if not set) and, optionally, a storage's name fromPIQ_STORAGE. Without a key the program stops at once. Requestis the JSON body of every request. Its fields are tagged with the API's camelCase names andomitempty, so only those set are sent:Template(the template's text) or, whenPIQ_STORAGEis set,Source(where it is kept in your storage), thenValuesand, to save,DestinationandOverwrite.postsends a request to an operation as JSON, with the key in theX-API-KEYheader. A success is handed back to be read. Any other response has its status printed, then its problem description: itsTitle, itsDetail, and each entry ofErrors, the field and what is wrong with it. A401has no body, so there is nothing more to print; a body that isn't JSON is printed as it is. The program then exits with1.postForposts and decodes the JSON answer into a struct with only the fields used here (encoding/jsonmatcheswidthtoWidthwithout tags).- Inputs.
POST /inputsneeds only the template. Each of itsInputshas a name, label, kind and value; the value isany, since it may be a number, text ortrueorfalse. - Measure. The values are added to the request, and
POST /measuregives the drawing's width and height, and its lines' lengths by layer; the cut length is the length on theCutlayer. - Export.
POST /export/pdfanswers with the PDF itself, not JSON: its body is written tobox.pdf. TheX-PiQ-Warningsheader says how many things couldn't be exported as they are. - Save (optional). With a storage,
DestinationandOverwriteare added, andPOST /save/pdfexports the same drawing and saves it to your storage, replacing a file already there. It answers with where it saved it and its size.
Running it
Save the program as main.go in a folder of its own, then:
export PIQ_API_KEY=XXXX-XXXX-XXXX-XXXXX
go run main.go
It prints the template's labelled variables, the drawing's size and cut length, and saves box.pdf:
L: Length (Number, 400)
W: Width (Number, 300)
D: Depth (Number, 300)
Size: 500 x 250, cut length: 1500
Saved box.pdf (0 warnings)
With a value the template can't use ("L": "long", say), it prints the problem and stops:
Error 400 Bad Request
One or more validation errors occurred.
Some of the values given can't be used.
L: L is a number.
With a key that isn't right it prints only Error 401 Unauthorized: a 401 has no
problem description.
To try the storage part, register a storage (see Register a storage), put a template in
it as templates/box.piq, and set PIQ_STORAGE to the storage's name. The template is then read from your storage,
and the PDF is also saved to it as drawings/box.pdf, replacing any file already there.
See also: API, Inputs, Measure, Export a drawing, Save to your storage, Register a storage, Clients.