mattpolzin / JSONAPI

Swift Codable JSON:API framework
MIT License
75 stars 19 forks source link

Batch document and single document #59

Closed ZahraAsgharzadeh closed 4 years ago

ZahraAsgharzadeh commented 4 years ago

hi again ... I'm using your library for a weak . I should say that it is very clear and easy to use, thanks alot , I have another question : I have several resource description structures that I define Resource typealias for each of them . I saw in your examples that you define Batch document and single document typealias, but in my case they are different for each resource description structure . for example one of them have meta data and one of them have different includes . So how can I define batch document and single document ? now I define both batch document and single document as typealias in each resource description structure , but I guess that it may cause problems . Could you please help me in this case too ?

mattpolzin commented 4 years ago

I'm glad you're finding the library easy to use. Thanks for the feedback!

Feel free to provide me more details so I can be more specific, but I think I can answer your question broadly. I would personally create typealiases that only define away the aspects of my document that are most likely to change. Some of my examples create overly specific type aliases because in the context of the example there is no need for them to be more generally applicable.

Here's a bit of pseudo-code to expound upon that.

// let's say I have two resource types
typealias Widget = JSONAPI.ResourceObject<...>
typealias Customer = JSONAPI.ResourceObject<...>

// first, in this hypothetical example, I won't parse the `APIDescription`, 
// I never expect to need to parse `Links` objects, and I always expect
// to parse a `BasicJSONAPIError` so I will define a typealiase that
// removes the constant factors from consideration.
typealias Document<PrimaryResourceBody: JSONAPI.EncodableResourceBody, MetaType: JSONAPI.Meta, IncludeType: JSONAPI.Include> = JSONAPI.Document<PrimaryResourceBody, MetaType, NoLinks, IncludeType, NoAPIDescription, BasicJSONAPIError<String>>

// My new Document typealias shadows the JSONAPI type, so I can now use my
// type as `Document` or access the JSONAPI type as `JSONAPI.Document`.

// This typealias means I have gone from needing to specialize my documents on
// 6 types to only needing to specialize them on 3 types.

// At this point, I may already be done because it is not really that unwieldy
// to use the above typealias.
let singleWidgetResponse: Document<SingleResourceBody<Widget>, NoMetadata, Include1<Widget>> = ...
let batchCustomerResponse: Document<ManyResourceBody<Customer>, CustomerMeta1, Include2<Customer, Widget>> = ...

// But, if I want I can move the "single"/"many" information into a new typealiases as well
// and I might consider that to offer better legibility.
typealias SingleDocument<PrimaryResource: JSONAPI.OptionalEncodablePrimaryResource, MetaType: JSONAPI.Meta, IncludeType: JSONAPI.Include> = Document<SingleResourceBody<PrimaryResource>, MetaType, IncludeType>
typealias BatchDocument<PrimaryResource: JSONAPI.EncodablePrimaryResource, MetaType: JSONAPI.Meta, IncludeType: JSONAPI.Include> = Document<ManyResourceBody<PrimaryResource>, MetaType, IncludeType>

// now the above two example documents become
let singleWidgetResponse2: SingleDocument<Widget, NoMetadata, Include1<Widget>> = ...
let batchCustomerResponse2: BatchDocument<Customer, CustomerMeta1, Include2<Customer, Widget>> = ...

// I would definitely stop here, but I'll play it out further because it's all a matter
// of personal preference in your codebase.

// I know I will sometimes want one `Widget` and other times many of them
// but I will always expect no metadata with my widgets.
typealias SingleWidgetDocument<IncludeType: JSONAPI.Include> = SingleDocument<Widget, NoMetadata, IncludeType>
typealias BatchWidgetDocument<IncludeType: JSONAPI.Include> = BatchDocument<Widget, NoMetadata, IncludeType>

// I know I will sometimes want one `Customer` and other times many of them
// but I also know I will sometimes want one metadata structure `CustomerMeta1`
// and other times I will want a different metadata structure `CustomerMeta2`.
typealias SingleCustomerDocument<MetaType: JSONAPI.Meta, IncludeType: JSONAPI.Include> = SingleDocument<Customer, MetaType, IncludeType>
typealias BatchCustomerDocument<MetaType: JSONAPI.Meta, IncludeType: JSONAPI.Include> = BatchDocument<Customer, MetaType, IncludeType>

// now the above two example documents become
let singleWidgetResponse3: SingleWidgetDocument<Include1<Widget>> = ...
let batchCustomerResponse3: BatchCustomerDocument<CustomerMeta1, Include2<Customer, Widget>> = ...

I hope this helps paint a picture of how typealiases could be defined differently in different codebases in order to more directly target the use-cases. There's no reason why the above example could not have resulted in typealiases that differentiate responses based on whether or not they have metadata instead of- or in addition to whether they contain one primary resource or many of them.

ZahraAsgharzadeh commented 4 years ago

Thanks for your explanation , I find way .