Open chr0n1x opened 9 years ago
@chr0n1x working on links, meta, and errors atm
:+1: :smile:
@shwoodard do you have an ETA? Or need help? Both?
@chr0n1x I have been working hard on how to specify the links
hashes throughout the response. Are the errors
objects more urgent to you? I could work on these first.
actually, paginated results / links are a big deal. keep at it! :+1:
@chr0n1x Can you help test and document?
Looking forward to this as well :smile:
Thanks for the library!
Checking in to see if you need help testing/documenting links.
@shwoodard Still looking for help? Tried your json_extras branch and looks like you are close.
@swr would love some help! ping me if still interested.!
@shwoodard Should have some bandwidth this week.
Given the JSON API specification surrounding errors (http://jsonapi.org/format/#errors) - noting that all fields are optional - is there a rough idea on how this would be implemented?
Examples in the spec are here: http://jsonapi.org/examples/#error-objects-basics - the major challenges I see are automating the source
/ pointer
detail - other fields like status
/ code
/ title
would typically be driven by the package user's application.
{
"errors": [
{
"status": "422",
"source": { "pointer": "/data/attributes/first-name" },
"title": "Invalid Attribute",
"detail": "First name must contain at least three characters."
}
]
}
@elithrar I would say that sticking to the spec and just doing a recursive reflect
on struct fields & values would be enough for a first rev. I believe that anything more should be left to the user, as the spec seems to imply.
@shwoodard sorry about the lack of response, my schedule has been fairly packed :(
Ola, another Gopher weighing in. What can I do to get this into master
?
Any updates on this?
:+1:
Commencing work on this right after supporting embedded structs.
what will be the reason for jsonapi to through EOF err
jsonapi.UnMarshalPayload(c.Request.Body,user)
is returning EOF
c.Request.Body
contains the json which is marshalled using jsonapi
Please help me with this
Show your code. You will typically see an EOF when you are trying to Unmarshal an empty body. On Wed, May 4, 2016 at 3:36 AM Rishiraj Shengule notifications@github.com wrote:
what will be the reason for jsonapi to through EOF err jsonapi.UnMarshalPayload() is returning EOF
Please help me with this
— You are receiving this because you were mentioned. Reply to this email directly or view it on GitHub https://github.com/shwoodard/jsonapi/issues/3#issuecomment-216824647
Thanks for your reply Below is the request I am sending (marshalled JSON using JSONAPI)
{
"data": {
"type": "users",
"id": "1",
"attributes": {
"company": "Torant",
"contact": "12345678",
"description": "hdgfsdfg",
"email": "abc@abc.com",
"first-name": "ABC",
"job-title": "xyz",
"last-name": "DEF",
"secContact": "434545665",
"username": "abc123",
"yearsOfExp": "5"
},
"relationships": {
"address": {
"data": [{
"type": "address",
"id": "2"
}]
}
}
},
"included": [{
"type": "address",
"id": "2",
"attributes": {
"city": "PU",
"country": "INDIA",
"state": "MH",
"street": "ahbfshdf",
"zipcode": "12345"
}
}]
}
Below is the struct that I am using in my code:
type Address struct {
Id string `jsonapi:"primary,address"`
Country string `jsonapi:"attr,country" `
State string `jsonapi:"attr,state" `
City string `jsonapi:"attr,city" `
Street string `jsonapi:"attr,street" `
Zipcode string `jsonapi:"attr,zipcode"`
}
type UserVO struct {
ID string `jsonapi:"primary,users"`
FirstName string `jsonapi:"attr,first-name"`
LastName string `jsonapi:"attr,last-name"`
Username string `jsonapi:"attr,username"`
Contact string `jsonapi:"attr,contact"`
SecondaryContact string `jsonapi:"attr,secContact"`
Email string `jsonapi:"attr,email"`
Company string `jsonapi:"attr,company"`
Jobtitle string `jsonapi:"attr,job-title"`
YearsOfExp string `jsonapi:"attr,yearsOfExp"`
Description string `jsonapi:"attr,description"`
Address []*Address `jsonapi:"relation,address"`
}
and here is the function:
func (c Users) Register() revel.Result {
user := new(models.UserVO)
user.ID = "12345"
buf := bytes.NewBuffer(nil)
io.Copy(buf, c.Request.Body)
fmt.Println(buf.String())
if err := jsonapi.UnmarshalPayload(c.Request.Body, user); err != nil {
// will be replace by JSONAPI
c.Response.Status = http.StatusExpectationFailed
fmt.Println(err)
return c.RenderText("could not parse request")
}
c.Response.Status = http.StatusCreated
return c.RenderJson(user)
}
@rishirajdev I can't seem to replicate your error; here is the go file I'm working with:
package issue
import (
"bytes"
"testing"
"github.com/shwoodard/jsonapi"
)
type Address struct {
Id string `jsonapi:"primary,address"`
Country string `jsonapi:"attr,country" `
State string `jsonapi:"attr,state" `
City string `jsonapi:"attr,city" `
Street string `jsonapi:"attr,street" `
Zipcode string `jsonapi:"attr,zipcode"`
}
type UserVO struct {
ID string `jsonapi:"primary,users"`
FirstName string `jsonapi:"attr,first-name"`
LastName string `jsonapi:"attr,last-name"`
Username string `jsonapi:"attr,username"`
Contact string `jsonapi:"attr,contact"`
SecondaryContact string `jsonapi:"attr,secContact"`
Email string `jsonapi:"attr,email"`
Company string `jsonapi:"attr,company"`
Jobtitle string `jsonapi:"attr,job-title"`
YearsOfExp string `jsonapi:"attr,yearsOfExp"`
Description string `jsonapi:"attr,description"`
Address []*Address `jsonapi:"relation,address"`
}
func TestPayload(t *testing.T) {
payload := bytes.NewBufferString(`
{
"data": {
"type": "users",
"id": "1",
"attributes": {
"company": "Torant",
"contact": "12345678",
"description": "hdgfsdfg",
"email": "abc@abc.com",
"first-name": "ABC",
"job-title": "xyz",
"last-name": "DEF",
"secContact": "434545665",
"username": "abc123",
"yearsOfExp": "5"
},
"relationships": {
"address": {
"data": [{
"type": "address",
"id": "2"
}]
}
}
},
"included": [{
"type": "address",
"id": "2",
"attributes": {
"city": "PU",
"country": "INDIA",
"state": "MH",
"street": "ahbfshdf",
"zipcode": "12345"
}
}]
}`)
user := &UserVO{}
if err := jsonapi.UnmarshalPayload(payload, user); err != nil {
t.Fatal(err)
}
// Random Validations
if user.ID != "1" || user.Company != "Torant" || user.Address[0].Id != "2" || user.Address[0].Country != "INDIA" {
t.Fatal("Fields in unmarshaled payload were not as expected")
}
}
See #52 for a proposed update if interested in pagination
Hey dudes - #57 and #58
Now that we're on track for Links (wahoo!)
Regarding Error objects.. Perhaps the right way to handle this would be something like MarshalManyError or MarshalOneError. This example (from examples/app.go) then goes from this:
if err := jsonapiRuntime.MarshalOnePayload(w, blog); err != nil {
http.Error(w, err.Error(), 500)
}
To this:
if err := jsonapiRuntime.MarshalOnePayload(w, blog); err != nil {
jsonapiRuntime.MarshalOneError(w, err.Error(), 500)
}
Which would produce:
Status: 500
{
errors: [{ title: "Some error occured"}]
}
Something like that?
JSONAPI error responses are always arrays (at least, as I understand it).
You are correct, @genexp. According to the spec, errors
must always be an array of error objects:
A document MUST contain at least one of the following top-level members:
data
: the document’s “primary data”errors
: an array of error objectsmeta
: a meta object that contains non-standard meta-information.The members
data
anderrors
MUST NOT coexist in the same document.
I would say that, at a minimum, we should include the title
field in the error, as well as the detail
field. The spec describes pretty well what the difference between these two fields should be.
All, please see PR #38. It is currently in a state which may completely address the items discussed here. A few notes to keep in mind:
The members 'data' and 'errors' MUST NOT coexist in the same document
according to the JSON API spec (see my comment immediately above this one).'errors': an array of error objects
according to the spec.Given those two points, I've created the type ErrorObject struct
which implements Error
as well as a few other interfaces which allow it to be used seamlessly with the new func MarshalErrors(w io.Writer, errs []error) error
. This func's call signature is quite similar to our other Marshal...
funcs.
There is also a series of public interfaces to be used by package consumers. These interfaces define a way of implementing error objects which will work seamlessly with MarshalErrors
.
@chr0n1x this implements the items you've mentioned throughout this issue.
@elithrar this implements the items that you mentioned above as well — though not the "source": { "pointer": "/data/attributes/first-name" },
system yet, I've left that as a TODO
for later, as this PR is fairly large already!
@genexp this implements the items that you've mentioned above as well. Namely the jsonapiRuntime.MarshalOneError(w, err.Error(), 500)
bits, with only a few deviations. Also, in the name of allowing this package to be used in as many different frameworks as possible, it looks like setting of a response status is typically left out of this package's routines. It can always be done by the user before calling this method.
Let me know if you have any feedback.
Looks like @thedodd is close. See above.
Very nice!
I believe that we can close this issue now, since the work in #38 has been merged. Thoughts?
@theodd Is there a way to unmarshal errors? not sure if I'm missing something.
Note: Shoud probably see #110 which is not specifically related to errors, but deals with other top level objects that we currently cannot really include.
Couldn't find anything in the code that did this, sorry if I'm misreading stuff. I think the specs are describing something like:
??