jsonapi/examples/app.go

199 lines
4.2 KiB
Go

package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/http/httptest"
"reflect"
"regexp"
"time"
"github.com/shwoodard/jsonapi"
)
func createBlog(w http.ResponseWriter, r *http.Request) {
blog := new(Blog)
if err := jsonapi.UnmarshalPayload(r.Body, blog); err != nil {
http.Error(w, err.Error(), 500)
return
}
// ...do stuff with your blog ...
w.WriteHeader(201)
w.Header().Set("Content-Type", "application/vnd.api+json")
if err := jsonapi.MarshalOnePayload(w, blog); err != nil {
http.Error(w, err.Error(), 500)
}
}
func listBlogs(w http.ResponseWriter, r *http.Request) {
// ... fetch your blogs and filter, offset, limit, etc ...
blogs := testBlogsForList()
w.WriteHeader(200)
w.Header().Set("Content-Type", "application/vnd.api+json")
if err := jsonapi.MarshalManyPayload(w, reflect.ValueOf(blogs)); err != nil {
http.Error(w, err.Error(), 500)
}
}
func main() {
http.HandleFunc("/blogs", func(w http.ResponseWriter, r *http.Request) {
if !regexp.MustCompile(`application/vnd\.api\+json`).Match([]byte(r.Header.Get("Accept"))) {
http.Error(w, "Not Acceptable", 406)
return
}
if r.Method == "POST" {
createBlog(w, r)
} else {
listBlogs(w, r)
}
})
exerciseHandler()
}
func testBlogForCreate(i int) *Blog {
return &Blog{
Id: 1 * i,
Title: "Title 1",
CreatedAt: time.Now(),
Posts: []*Post{
&Post{
Id: 1 * i,
Title: "Foo",
Body: "Bar",
Comments: []*Comment{
&Comment{
Id: 1 * i,
Body: "foo",
},
&Comment{
Id: 2 * i,
Body: "bar",
},
},
},
&Post{
Id: 2 * i,
Title: "Fuubar",
Body: "Bas",
Comments: []*Comment{
&Comment{
Id: 1 * i,
Body: "foo",
},
&Comment{
Id: 3 * i,
Body: "bas",
},
},
},
},
CurrentPost: &Post{
Id: 1 * i,
Title: "Foo",
Body: "Bar",
Comments: []*Comment{
&Comment{
Id: 1 * i,
Body: "foo",
},
&Comment{
Id: 2 * i,
Body: "bar",
},
},
},
}
}
func testBlogsForList() []interface{} {
blogs := make([]interface{}, 0, 10)
for i := 0; i < 10; i += 1 {
blogs = append(blogs, testBlogForCreate(i))
}
return blogs
}
func exerciseHandler() {
req, _ := http.NewRequest("GET", "/blogs", nil)
req.Header.Set("Accept", "application/vnd.api+json")
w := httptest.NewRecorder()
http.DefaultServeMux.ServeHTTP(w, req)
buf := new(bytes.Buffer)
io.Copy(buf, w.Body)
fmt.Println("============ jsonapi response from list ===========\n")
fmt.Println(buf.String())
fmt.Println("============== end raw jsonapi from list =============")
blog := testBlogForCreate(1)
in := bytes.NewBuffer(nil)
jsonapi.MarshalOnePayloadEmbedded(in, blog)
req, _ = http.NewRequest("POST", "/blogs", in)
req.Header.Set("Accept", "application/vnd.api+json")
w = httptest.NewRecorder()
http.DefaultServeMux.ServeHTTP(w, req)
buf = new(bytes.Buffer)
io.Copy(buf, w.Body)
fmt.Println("\n============ jsonapi response from create ===========\n")
fmt.Println(buf.String())
fmt.Println("============== end raw jsonapi response =============")
responseBlog := new(Blog)
jsonapi.UnmarshalPayload(buf, responseBlog)
out := bytes.NewBuffer(nil)
json.NewEncoder(out).Encode(responseBlog)
fmt.Println("\n================ Viola! Converted back our Blog struct =================\n")
fmt.Printf("%s\n", out.Bytes())
fmt.Println("================ end marshal materialized Blog struct =================")
}
type Blog struct {
Id int `jsonapi:"primary,blogs"`
Title string `jsonapi:"attr,title"`
Posts []*Post `jsonapi:"relation,posts"`
CurrentPost *Post `jsonapi:"relation,current_post"`
CurrentPostId int `jsonapi:"attr,current_post_id"`
CreatedAt time.Time `jsonapi:"attr,created_at"`
ViewCount int `jsonapi:"attr,view_count"`
}
type Post struct {
Id int `jsonapi:"primary,posts"`
BlogId int `jsonapi:"attr,blog_id"`
Title string `jsonapi:"attr,title"`
Body string `jsonapi:"attr,body"`
Comments []*Comment `jsonapi:"relation,comments"`
}
type Comment struct {
Id int `jsonapi:"primary,comments"`
PostId int `jsonapi:"attr,post_id"`
Body string `jsonapi:"attr,body"`
}