Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom types (#114) #115

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open

Conversation

xcoulon
Copy link

@xcoulon xcoulon commented Sep 13, 2017

This applies to:

  • ID
  • Attributes
  • Relationships

Custom types need to be registered before usage, using the new
jsonapi.RegisterType() function which takes 3 arguments:

  • the type to support (reflect.Type)
  • the function to use when marshalling a response
  • the function to use when unmarshalling a response

Example:

RegisterType(uuidType,
  func(value interface{}) (string, error) {
    result := value.(*UUID).String()
    return result, nil
  },
  func(value string) (interface{}, error) {
    return UUIDFromString(value)
  })

The custom type will be represented as a string in the JSON document
in the requests and responses.

Fixes #114

Signed-off-by: Xavier Coulon [email protected]

@googlebot
Copy link

Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

📝 Please visit https://cla.developers.google.com/ to sign.

Once you've signed, please reply here (e.g. I signed it!) and we'll verify. Thanks.


  • If you've already signed a CLA, it's possible we don't have your GitHub username or you're using a different email address. Check your existing CLA data and verify that your email is set on your git commits.
  • If your company signed a CLA, they designated a Point of Contact who decides which employees are authorized to participate. You may need to contact the Point of Contact for your company and ask to be added to the group of authorized contributors. If you don't know who your Point of Contact is, direct the project maintainer to go/cla#troubleshoot.
  • In order to pass this check, please resolve this problem and have the pull request author add another comment and the bot will run again.

@xcoulon
Copy link
Author

xcoulon commented Sep 13, 2017

I just signed the CLA.

@googlebot
Copy link

CLAs look good, thanks!

This applies to:
- ID
- Attributes
- Relationships

Custom types need to be registered before usage, using the new
`jsonapi.RegisterType()` function which takes 3 arguments:
- the type to support (`reflect.Type`)
- the function to use when marshalling a response
- the function to use when unmarshalling a response

Example:
````
RegisterType(uuidType,
  func(value interface{}) (string, error) {
    result := value.(*UUID).String()
    return result, nil
  },
  func(value string) (interface{}, error) {
    return UUIDFromString(value)
  })
````

The custom type will be represented as a `string` in the JSON document
in the requests and responses.

Fixes google#114

Signed-off-by: Xavier Coulon <[email protected]>
@bridgetlane
Copy link

+1

@shwoodard
Copy link
Contributor

Please remove prints from tests so go test -v is clean

Copy link
Contributor

@shwoodard shwoodard left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should not marshal/unmarshal to/from string but rather interface{}. What if you want a number to go to a custom type? Input/output may not be a string.

Store state of return type by making type CustomType reflect.Type

Don't assume is custom type. Should be declared explicitly. IOW, add a comma separated value to struct tag, "custom", and add to constants.go.

var customTypeUnmarshallingFuncs map[reflect.Type]UnmarshallingFunc

// init initializes the maps
func init() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use init(), don't use make, use var in block, e.g.

var (
    customTypeMarshallingFuncs = map[reflect.Type]MarshallingFunc{}
    cutomTypeUnmarshallingFuncs = map[reflect.Type]UnmarshallingFunc{}
)

See,
https://play.golang.org/p/OnktgftaGQ


import "reflect"

type MarshallingFunc func(interface{}) (string, error)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow pattern of net/http's http.Handle and http.HandleFunc, and don't rely on input/output being string e.g.

type TypeMarshaller interface {
    Marshal(interface{}) (interface{}, error)
}

type TypeUnmarshaller interface {
    UnMarshal(interface{}) (interface{}, error)
}

type TypeMarshalFunc func(interface{}) (interface{}, error)

func (tmf TypeMarshalFunc) func(thing interface{}) (interface{}, error) {
    return tmf(thing)
}

type TypeUnmarshalFunc func(interface{}) (interface{}, error)

func (tuf TypeUnmarshalFunc) func(thing interface{}) (interface{}, error) {
    return tuf(thing)
}

Then you can have RegisterCustomType(in, out reflect.Type, marshaller TypeMarshaller, unmarshaller TypeUnmarshaller) and RegisterCustomTypeFunc(in, out reflect.Type, marshallerFunc TypeMarshallerFunc, unmarshallerFunc TypeUnmarshallerFunc)`

@shwoodard
Copy link
Contributor

I'm working on changing this. See wip @ https://github.com/shwoodard/jsonapi/blob/custom_types/custom_types.go

@xcoulon
Copy link
Author

xcoulon commented Nov 9, 2017

thanks for the review, @shwoodard ! I'm not sure I understood your last comment: do you mean I should abandon this PR since you're working on it, too ?

@mithmatt
Copy link

mithmatt commented Dec 9, 2017

@shwoodard @xcoulon

I reviewed this pull request and also took a look at https://github.com/shwoodard/jsonapi/blob/custom_types/custom_types.go

Package encoding/json has Marshaler and Unmarshaler interfaces. Can we leverage these interfaces for custom types? This would avoid having users to call out custom types, the marshal and unmarshal functions explicitly through a register function.

There are numerous packages out there, which auto generates code to create MarshalJSON and UnmarshalJSON, such alvaroloes/enumer for enums.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants