jsonapi/examples/app.go

292 lines
7.2 KiB
Go
Raw Normal View History

2015-07-10 16:50:51 -04:00
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
2015-07-19 13:32:07 -04:00
"io/ioutil"
2015-07-10 16:50:51 -04:00
"net/http"
"net/http/httptest"
"regexp"
2015-07-19 13:32:07 -04:00
"strconv"
2015-07-10 16:50:51 -04:00
"time"
"github.com/google/jsonapi"
2015-07-10 16:50:51 -04:00
)
func createBlog(w http.ResponseWriter, r *http.Request) {
jsonapiRuntime := jsonapi.NewRuntime().Instrument("blogs.create")
2015-07-10 16:50:51 -04:00
blog := new(Blog)
if err := jsonapiRuntime.UnmarshalPayload(r.Body, blog); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
2015-07-10 16:50:51 -04:00
return
}
2015-07-19 13:32:07 -04:00
// ...do stuff with your blog...
2015-07-10 16:50:51 -04:00
w.WriteHeader(http.StatusCreated)
w.Header().Set("Content-Type", jsonapi.MediaType)
2015-07-10 16:50:51 -04:00
if err := jsonapiRuntime.MarshalOnePayload(w, blog); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
2015-07-10 16:50:51 -04:00
}
}
func listBlogs(w http.ResponseWriter, r *http.Request) {
jsonapiRuntime := jsonapi.NewRuntime().Instrument("blogs.list")
2015-07-19 13:32:07 -04:00
// ...fetch your blogs, filter, offset, limit, etc...
2015-07-10 16:50:51 -04:00
2015-07-19 13:32:07 -04:00
// but, for now
2015-07-12 13:46:51 -04:00
blogs := testBlogsForList()
2015-07-10 16:50:51 -04:00
w.WriteHeader(http.StatusOK)
w.Header().Set("Content-Type", jsonapi.MediaType)
if err := jsonapiRuntime.MarshalManyPayload(w, blogs); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
2015-07-12 13:46:51 -04:00
}
2015-07-10 16:50:51 -04:00
}
2015-07-19 13:32:07 -04:00
func showBlog(w http.ResponseWriter, r *http.Request) {
id := r.FormValue("id")
// ...fetch your blog...
2016-07-05 21:32:15 -04:00
intID, err := strconv.Atoi(id)
2015-07-19 13:32:07 -04:00
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
2015-07-19 13:32:07 -04:00
}
jsonapiRuntime := jsonapi.NewRuntime().Instrument("blogs.show")
2015-07-19 13:32:07 -04:00
// but, for now
2016-07-05 21:32:15 -04:00
blog := testBlogForCreate(intID)
w.WriteHeader(http.StatusOK)
2015-07-19 13:32:07 -04:00
w.Header().Set("Content-Type", jsonapi.MediaType)
if err := jsonapiRuntime.MarshalOnePayload(w, blog); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
2015-07-19 13:32:07 -04:00
}
}
2015-07-12 13:46:51 -04:00
func main() {
jsonapi.Instrumentation = func(r *jsonapi.Runtime, eventType jsonapi.Event, callGUID string, dur time.Duration) {
metricPrefix := r.Value("instrument").(string)
if eventType == jsonapi.UnmarshalStart {
fmt.Printf("%s: id, %s, started at %v\n", metricPrefix+".jsonapi_unmarshal_time", callGUID, time.Now())
}
if eventType == jsonapi.UnmarshalStop {
2016-03-27 14:44:52 -04:00
fmt.Printf("%s: id, %s, stopped at, %v , and took %v to unmarshal payload\n", metricPrefix+".jsonapi_unmarshal_time", callGUID, time.Now(), dur)
}
if eventType == jsonapi.MarshalStart {
fmt.Printf("%s: id, %s, started at %v\n", metricPrefix+".jsonapi_marshal_time", callGUID, time.Now())
}
if eventType == jsonapi.MarshalStop {
2016-03-27 14:44:52 -04:00
fmt.Printf("%s: id, %s, stopped at, %v , and took %v to marshal payload\n", metricPrefix+".jsonapi_marshal_time", callGUID, time.Now(), dur)
}
}
2015-07-12 13:46:51 -04:00
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, "Unsupported Media Type", http.StatusUnsupportedMediaType)
2015-07-12 13:46:51 -04:00
return
}
if r.Method == http.MethodPost {
2015-07-12 13:46:51 -04:00
createBlog(w, r)
2015-07-19 13:32:07 -04:00
} else if r.FormValue("id") != "" {
showBlog(w, r)
2015-07-12 13:46:51 -04:00
} else {
listBlogs(w, r)
}
})
exerciseHandler()
2015-07-10 16:50:51 -04:00
}
2015-07-12 13:46:51 -04:00
func testBlogForCreate(i int) *Blog {
2015-07-10 16:50:51 -04:00
return &Blog{
2016-07-05 21:32:15 -04:00
ID: 1 * i,
2015-07-10 16:50:51 -04:00
Title: "Title 1",
CreatedAt: time.Now(),
Posts: []*Post{
&Post{
2016-07-05 21:32:15 -04:00
ID: 1 * i,
2015-07-10 16:50:51 -04:00
Title: "Foo",
Body: "Bar",
Comments: []*Comment{
&Comment{
2016-07-05 21:32:15 -04:00
ID: 1 * i,
2015-07-10 16:50:51 -04:00
Body: "foo",
},
&Comment{
2016-07-05 21:32:15 -04:00
ID: 2 * i,
2015-07-10 16:50:51 -04:00
Body: "bar",
},
},
},
&Post{
2016-07-05 21:32:15 -04:00
ID: 2 * i,
2015-07-10 16:50:51 -04:00
Title: "Fuubar",
Body: "Bas",
Comments: []*Comment{
&Comment{
2016-07-05 21:32:15 -04:00
ID: 1 * i,
2015-07-10 16:50:51 -04:00
Body: "foo",
},
&Comment{
2016-07-05 21:32:15 -04:00
ID: 3 * i,
2015-07-10 16:50:51 -04:00
Body: "bas",
},
},
},
},
CurrentPost: &Post{
2016-07-05 21:32:15 -04:00
ID: 1 * i,
2015-07-10 16:50:51 -04:00
Title: "Foo",
Body: "Bar",
Comments: []*Comment{
&Comment{
2016-07-05 21:32:15 -04:00
ID: 1 * i,
2015-07-10 16:50:51 -04:00
Body: "foo",
},
&Comment{
2016-07-05 21:32:15 -04:00
ID: 2 * i,
2015-07-10 16:50:51 -04:00
Body: "bar",
},
},
},
}
}
2015-07-12 13:46:51 -04:00
func testBlogsForList() []interface{} {
blogs := make([]interface{}, 0, 10)
2015-07-12 13:46:51 -04:00
for i := 0; i < 10; i++ {
2015-07-12 13:46:51 -04:00
blogs = append(blogs, testBlogForCreate(i))
}
return blogs
}
func exerciseHandler() {
2015-07-19 13:32:07 -04:00
// list
req, _ := http.NewRequest(http.MethodGet, "/blogs", nil)
2015-07-12 13:46:51 -04:00
req.Header.Set("Accept", jsonapi.MediaType)
2015-07-12 13:46:51 -04:00
w := httptest.NewRecorder()
fmt.Println("============ start list ===========")
2015-07-12 13:46:51 -04:00
http.DefaultServeMux.ServeHTTP(w, req)
fmt.Println("============ stop list ===========")
2015-07-12 13:46:51 -04:00
2015-07-19 13:32:07 -04:00
jsonReply, _ := ioutil.ReadAll(w.Body)
2015-07-12 13:46:51 -04:00
fmt.Println("============ jsonapi response from list ===========")
2015-07-19 13:32:07 -04:00
fmt.Println(string(jsonReply))
2015-07-12 13:46:51 -04:00
fmt.Println("============== end raw jsonapi from list =============")
2015-07-19 13:32:07 -04:00
// show
req, _ = http.NewRequest(http.MethodGet, "/blogs?id=1", nil)
2015-07-19 13:32:07 -04:00
req.Header.Set("Accept", jsonapi.MediaType)
2015-07-19 13:32:07 -04:00
w = httptest.NewRecorder()
fmt.Println("============ start show ===========")
2015-07-19 13:32:07 -04:00
http.DefaultServeMux.ServeHTTP(w, req)
fmt.Println("============ stop show ===========")
2015-07-19 13:32:07 -04:00
jsonReply, _ = ioutil.ReadAll(w.Body)
fmt.Println("\n============ jsonapi response from show ===========")
2015-07-19 13:32:07 -04:00
fmt.Println(string(jsonReply))
fmt.Println("============== end raw jsonapi from show =============")
// create
2015-07-12 13:46:51 -04:00
blog := testBlogForCreate(1)
in := bytes.NewBuffer(nil)
jsonapi.MarshalOnePayloadEmbedded(in, blog)
req, _ = http.NewRequest(http.MethodPost, "/blogs", in)
2015-07-12 13:46:51 -04:00
req.Header.Set("Accept", jsonapi.MediaType)
2015-07-12 13:46:51 -04:00
w = httptest.NewRecorder()
fmt.Println("============ start create ===========")
2015-07-12 13:46:51 -04:00
http.DefaultServeMux.ServeHTTP(w, req)
fmt.Println("============ stop create ===========")
2015-07-12 13:46:51 -04:00
2015-07-19 13:32:07 -04:00
buf := bytes.NewBuffer(nil)
2015-07-12 13:46:51 -04:00
io.Copy(buf, w.Body)
fmt.Println("\n============ jsonapi response from create ===========")
2015-07-12 13:46:51 -04:00
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 =================")
2015-07-12 13:46:51 -04:00
fmt.Printf("%s\n", out.Bytes())
fmt.Println("================ end marshal materialized Blog struct =================")
}
type Blog struct {
2016-07-05 21:32:15 -04:00
ID int `jsonapi:"primary,blogs"`
2015-07-12 13:46:51 -04:00
Title string `jsonapi:"attr,title"`
Posts []*Post `jsonapi:"relation,posts"`
CurrentPost *Post `jsonapi:"relation,current_post"`
2016-07-05 21:32:15 -04:00
CurrentPostID int `jsonapi:"attr,current_post_id"`
2015-07-12 13:46:51 -04:00
CreatedAt time.Time `jsonapi:"attr,created_at"`
ViewCount int `jsonapi:"attr,view_count"`
}
type Post struct {
2016-07-05 21:32:15 -04:00
ID int `jsonapi:"primary,posts"`
BlogID int `jsonapi:"attr,blog_id"`
2015-07-12 13:46:51 -04:00
Title string `jsonapi:"attr,title"`
Body string `jsonapi:"attr,body"`
Comments []*Comment `jsonapi:"relation,comments"`
}
type Comment struct {
2016-07-05 21:32:15 -04:00
ID int `jsonapi:"primary,comments"`
PostID int `jsonapi:"attr,post_id"`
2015-07-12 13:46:51 -04:00
Body string `jsonapi:"attr,body"`
}
// Blog Links
func (blog Blog) JSONAPILinks() *map[string]interface{} {
return &map[string]interface{}{
"self": fmt.Sprintf("https://example.com/blogs/%d", blog.ID),
}
}
func (blog Blog) JSONAPIRelationshipLinks(relation string) *map[string]interface{} {
if relation == "posts" {
return &map[string]interface{}{
"related": fmt.Sprintf("https://example.com/blogs/%d/posts", blog.ID),
}
}
if relation == "current_post" {
return &map[string]interface{}{
"related": fmt.Sprintf("https://example.com/blogs/%d/current_post", blog.ID),
}
}
return nil
}