Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
bfad8d9
Updated references.
RichardKnop Jul 29, 2016
b024b79
Decoupled tests from the main package.
RichardKnop Aug 2, 2016
084d1f8
Added .travis.yml
RichardKnop Oct 28, 2016
09ba9b0
Update README.md
RichardKnop Oct 28, 2016
a4ad8df
Added DecodeEmbedded method plus tests.
RichardKnop Jan 5, 2017
b16f4c9
Added CountEmbedded method.
RichardKnop Jan 5, 2017
ce3d531
Can count embedded map now.
RichardKnop Jan 16, 2017
5196104
Fixed comment typo.
RichardKnop Jan 16, 2017
c338b7f
Pulled upstream changes.
RichardKnop Apr 27, 2017
865dafd
Update README.md
RichardKnop May 7, 2017
2a6b44e
Added bitcoin donate button.
RichardKnop May 30, 2017
f407542
Updated .travis.yml
RichardKnop May 30, 2017
0346f03
Updated deps
RichardKnop May 30, 2017
b69dc3d
Added linters
RichardKnop Jun 2, 2017
858d9ec
Update README.md
RichardKnop Jun 2, 2017
aba4e46
Added codecov coverage.
RichardKnop Jun 19, 2017
72ff2ec
Separate Makefile command for running tests with coverage.
RichardKnop Jun 19, 2017
9f8d3f1
Change covermode to set and run tests in parallel.
RichardKnop Jun 19, 2017
1aed181
Updated deps
RichardKnop Jun 19, 2017
f05ce96
Fixing coverage report to aggregate results from all packages.
RichardKnop Jul 14, 2017
baa0c7e
Added mapstructure decoder to get support for json fields of type tim…
luedigernet Sep 27, 2017
3da4883
Merge branch 'feature/mapstructureDecodeTime' into develop
luedigernet Sep 27, 2017
dbe040d
Merge branch 'develop'
luedigernet Sep 27, 2017
eb1c2a8
removed json tag on unexported field
luedigernet Sep 27, 2017
9b42e9d
Merge branch 'develop'
luedigernet Sep 27, 2017
7972db1
Adjusted tests for new time fields.
luedigernet Sep 27, 2017
d21787d
Merge branch 'develop'
luedigernet Sep 27, 2017
4fc34cd
Fixed some metalinter complains
luedigernet Sep 27, 2017
3c4622a
switched import pathback to github.com/RichardKnop/jsonhal
luedigernet Sep 27, 2017
bce3985
Merge branch 'develop'
luedigernet Sep 27, 2017
6fa3f8f
Merge pull request #1 from luedigernet/master
RichardKnop Sep 27, 2017
b7afb94
Added some mapstructure tags
luedigernet Sep 28, 2017
1d2748b
Merge branch 'feature/mapstructureTags' into develop
luedigernet Sep 28, 2017
0a89b7a
Merge branch 'develop'
luedigernet Sep 28, 2017
6308bb1
Merge pull request #2 from luedigernet/master
RichardKnop Sep 28, 2017
7fdf3cf
Updated from godep to dep for dependency management.
RichardKnop Oct 2, 2017
95cb5de
Updated Makefile
RichardKnop Oct 10, 2017
9943f64
Updated dep cli tool and ran dep ensure -update
RichardKnop Nov 1, 2017
5ce2a85
Fixed gometalinter bug
RichardKnop Nov 1, 2017
a9cc8aa
Pruned dependencies.
RichardKnop Nov 1, 2017
14576f0
Update README.md
RichardKnop Dec 19, 2017
40578db
Update .travis.yml
RichardKnop Dec 19, 2017
8d8c680
Update Makefile
RichardKnop Dec 19, 2017
413eb82
Update README.md
RichardKnop May 26, 2018
dcc744e
Fix golint import path
golint-fixer Oct 25, 2018
5765dac
Merge pull request #3 from golint-fixer/master
RichardKnop Oct 26, 2018
d80ed0c
Update .travis.yml
RichardKnop Nov 1, 2018
4d331d3
Using modules for dependency management.
Nov 1, 2018
9ef775c
Removding unused files.
Nov 1, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
coverage*
17 changes: 17 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
language: go

go:
- 1.11.x

env:
- GO111MODULE=on

services:
- docker

script:
- make test-with-coverage

after_success:
- bash <(curl -s https://codecov.io/bash)
22 changes: 0 additions & 22 deletions Godeps/Godeps.json

This file was deleted.

5 changes: 0 additions & 5 deletions Godeps/Readme

This file was deleted.

45 changes: 30 additions & 15 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
DEPS=go list -f '{{range .TestImports}}{{.}} {{end}}' ./...
.PHONY: fmt lint golint test test-with-coverage
# TODO: When Go 1.9 is released vendor folder should be ignored automatically
PACKAGES=`go list ./... | grep -v vendor | grep -v mocks`

export GO15VENDOREXPERIMENT=1

update-deps:
rm -rf Godeps
rm -rf vendor
go get github.com/tools/godep
godep save ./...
fmt:
for pkg in ${PACKAGES}; do \
go fmt $$pkg; \
done;

install-deps:
go get github.com/tools/godep
godep restore
$(DEPS) | xargs -n1 go get -d
lint:
gometalinter --tests --disable-all --deadline=120s -E vet -E gofmt -E misspell -E ineffassign -E goimports -E deadcode ./...

fmt:
bash -c 'go list ./... | grep -v vendor | xargs -n1 go fmt'
golint:
for pkg in ${PACKAGES}; do \
golint -set_exit_status $$pkg || GOLINT_FAILED=1; \
done; \
[ -z "$$GOLINT_FAILED" ]

test:
bash -c 'go list ./... | grep -v vendor | xargs -n1 go test -timeout=10s'
TEST_FAILED= ; \
for pkg in ${PACKAGES}; do \
go test $$pkg || TEST_FAILED=1; \
done; \
[ -z "$$TEST_FAILED" ]

test-with-coverage:
echo "" > coverage.out
echo "mode: set" > coverage-all.out
TEST_FAILED= ; \
for pkg in ${PACKAGES}; do \
go test -coverprofile=coverage.out -covermode=set $$pkg || TEST_FAILED=1; \
tail -n +2 coverage.out >> coverage-all.out; \
done; \
[ -z "$$TEST_FAILED" ]
#go tool cover -html=coverage-all.out
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
[![Codeship Status for AreaHQ/jsonhal](https://codeship.com/projects/b2f1dac0-9da7-0133-7683-1a74f7994c2d/status?branch=master)](https://codeship.com/projects/127557)

# jsonhal
## jsonhal

A simple Go package to make custom structs marshal into [HAL](http://stateless.co/hal_specification.html) compatible JSON responses.

[![Travis Status for RichardKnop/jsonhal](https://travis-ci.org/RichardKnop/jsonhal.svg?branch=master&label=linux+build)](https://travis-ci.org/RichardKnop/jsonhal)
[![godoc for RichardKnop/jsonhal](https://godoc.org/github.com/nathany/looper?status.svg)](http://godoc.org/github.com/RichardKnop/jsonhal)
[![codecov for RichardKnop/jsonhal](https://codecov.io/gh/RichardKnop/jsonhal/branch/master/graph/badge.svg)](https://codecov.io/gh/RichardKnop/jsonhal)

---


Just add `jsonhal.Hal` as anonymous field to your structs and use `SetLink` to set hyperlinks and optionally `SetEmbedded` to set embedded resources.

Example:
Expand All @@ -15,7 +20,7 @@ import (
"encoding/json"
"log"

"github.com/AreaHQ/jsonhal"
"github.com/RichardKnop/jsonhal"
)

// HelloWorld ...
Expand Down
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module github.com/RichardKnop/jsonhal

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/mitchellh/mapstructure v1.1.2
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.2.2
)
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
9 changes: 9 additions & 0 deletions gometalinter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Linters":
{
"vet":
{
"Command": "go tool vet"
}
}
}
72 changes: 66 additions & 6 deletions jsonhal.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
package jsonhal

import (
"errors"
"fmt"
"reflect"
"time"

"github.com/mitchellh/mapstructure"
)

// Link represents a link in "_links" object
type Link struct {
Href string `json:"href"`
Title string `json:"title,omitempty"`
Href string `json:"href" mapstructure:"href"`
Title string `json:"title,omitempty" mapstructure:"title"`
}

// Embedded represents a resource in "_embedded" object
Expand All @@ -23,23 +28,24 @@ type EmbedSetter interface {
SetEmbedded(name string, embedded Embedded)
}

// EmbedSetter is the interface that wraps the basic setEmbedded method.
// EmbedGetter is the interface that wraps the basic getEmbedded method.
//
// GetEmbedded returns a slice of embedded resources by name or error
type EmbedGetter interface {
GetEmbedded(name string) (Embedded, error)
}

// Embeddeer is the interface that wraps the basic setEmbedded and getEmbedded methods.
// Embedder is the interface that wraps the basic setEmbedded and getEmbedded methods.
type Embedder interface {
EmbedSetter
EmbedGetter
}

// Hal is used for composition, include it as anonymous field in your structs
type Hal struct {
Links map[string]*Link `json:"_links,omitempty"`
Embedded map[string]Embedded `json:"_embedded,omitempty"`
Links map[string]*Link `json:"_links,omitempty" mapstructure:"_links"`
Embedded map[string]Embedded `json:"_embedded,omitempty" mapstructure:"_embedded"`
decoder *mapstructure.Decoder
}

// SetLink sets a link (self, next, etc). Title argument is optional
Expand Down Expand Up @@ -89,6 +95,60 @@ func (h *Hal) GetEmbedded(name string) (Embedded, error) {
return embedded, nil
}

// CountEmbedded counts number of embedded items
func (h *Hal) CountEmbedded(name string) (int, error) {
e, err := h.GetEmbedded(name)
if err != nil {
return 0, err
}
if reflect.TypeOf(interface{}(e)).Kind() != reflect.Slice && reflect.TypeOf(interface{}(e)).Kind() != reflect.Map {
return 0, errors.New("Embedded object is not a slice or a map")
}
return reflect.ValueOf(interface{}(e)).Len(), nil
}

// decodeHook is used to support datatypes that mapstructure does not support native
func (h *Hal) decodeHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {

// only if target datatype is time.Time and if source datatype is string
if t == reflect.TypeOf(time.Time{}) && f == reflect.TypeOf("") {
return time.Parse(time.RFC3339, data.(string))
}

//everything else would not be handled for now
return data, nil
}

// DecodeEmbedded decodes embedded objects into a struct
func (h *Hal) DecodeEmbedded(name string, result interface{}) (err error) {
var dec *mapstructure.Decoder
defer func() {
if r := recover(); r != nil {
err = r.(error)

}
}()

e, err := h.GetEmbedded(name)
if err != nil {
panic(err)
}
//setup a new decoder if not already present
if h.decoder == nil {
dec, err = mapstructure.NewDecoder(&mapstructure.DecoderConfig{Result: result, DecodeHook: h.decodeHook})
if err != nil {
panic(err)
}
h.decoder = dec
}

err = h.decoder.Decode(e)
if err != nil {
panic(err)
}
return nil
}

// DeleteEmbedded removes an embedded resource named name if it is found
func (h *Hal) DeleteEmbedded(name string) {
if h.Embedded != nil {
Expand Down
Loading