Skip to content

Commit

Permalink
Refactor hypermedia support to allow library users to use a different…
Browse files Browse the repository at this point in the history
… encoding strategy for hypermedia links

Avoid configuring hypermedia related mappings for non-hypermedia driven handlers
  • Loading branch information
gcotelli committed Jun 14, 2024
1 parent 22860d4 commit 0d6dfa1
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,35 @@ Class {
#tag : 'HATEOAS'
}

{ #category : 'encoding' }
HypermediaDrivenRESTfulRequestHandler class >> encode: resource toJsonUsing: writer as: schema within: requestContext [

writer
for: ResourceCollection do: [ :mapping |
( mapping mapInstVar: #items ) valueSchema: #ResourceCollectionItems.
mapping mapAsHypermediaControls: [ :collection |
requestContext hypermediaControlsFor: collection items ]
];
for: #ResourceCollectionItems customDo: [ :mapping | mapping listOfElementSchema: schema ].

[ writer nextPut: resource as: schema ]
unless: ( resource isA: ResourceCollection )
inWhichCase: [ writer nextPut: resource ]
]

{ #category : 'encoding' }
HypermediaDrivenRESTfulRequestHandler class >> encode: resource toJsonUsing: writer within: requestContext [

writer for: ResourceCollection do: [ :mapping |
mapping
mapInstVar: #items;
mapAsHypermediaControls: [ :collection |
requestContext hypermediaControlsFor: collection items ]
].

writer nextPut: resource
]

{ #category : 'instance creation' }
HypermediaDrivenRESTfulRequestHandler class >> resourceLocator: aResouceLocator paginationPolicy: aPaginationPolicy decodingRules: theDecodingRules encodingRules: theEncodingRules calculateEntityTagsWith: entityTagCalculator cachingDirectives: theCachingDirectives allowedLanguageTags: allowedLanguageTags drivenBy: aMediaControlsFactory handleErrorsWith: anExceptionHandler [

Expand Down
12 changes: 12 additions & 0 deletions source/Stargate-Model/RESTfulRequestHandler.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ Class {
#tag : 'Controllers'
}

{ #category : 'encoding' }
RESTfulRequestHandler class >> encode: resource toJsonUsing: writer as: schema within: requestContext [

writer nextPut: resource as: schema
]

Check warning on line 17 in source/Stargate-Model/RESTfulRequestHandler.class.st

View check run for this annotation

Codecov / codecov/patch

source/Stargate-Model/RESTfulRequestHandler.class.st#L14-L17

Added lines #L14 - L17 were not covered by tests

{ #category : 'encoding' }
RESTfulRequestHandler class >> encode: resource toJsonUsing: writer within: requestContext [

writer nextPut: resource
]

{ #category : 'instance creation' }
RESTfulRequestHandler class >> resourceLocator: aResouceLocator paginationPolicy: aPaginationPolicy decodingRules: theDecodingRules encodingRules: theEncodingRules calculateEntityTagsWith: entityTagCalculator cachingDirectives: theCachingDirectives allowedLanguageTags: allowedLanguageTags handleErrorsWith: anExceptionHandler [

Expand Down
12 changes: 12 additions & 0 deletions source/Stargate-Model/RESTfulRequestHandlerBehavior.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ Class {
#tag : 'Controllers'
}

{ #category : 'encoding' }
RESTfulRequestHandlerBehavior class >> encode: resource toJsonUsing: writer as: schema within: requestContext [

self subclassResponsibility
]

{ #category : 'encoding' }
RESTfulRequestHandlerBehavior class >> encode: resource toJsonUsing: writer within: requestContext [

self subclassResponsibility
]

{ #category : 'private' }
RESTfulRequestHandlerBehavior >> applyCachingDirectivesFor: aResource to: response within: requestContext [

Expand Down
148 changes: 71 additions & 77 deletions source/Stargate-Model/RESTfulRequestHandlerBuilder.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ Class {
'encodingRules',
'paginationPolicyFactory',
'entityTagFactoryBinding',
'handlerFactory',
'resourceLocator',
'exceptionHandler',
'cachingDirectives',
'allowedLanguageTags'
'allowedLanguageTags',
'requestHandlerClass',
'requestHandlerFactory'
],
#category : 'Stargate-Model-Controllers',
#package : 'Stargate-Model',
Expand All @@ -35,34 +36,37 @@ RESTfulRequestHandlerBuilder >> beHypermediaDriven [
{ #category : 'configuring' }
RESTfulRequestHandlerBuilder >> beHypermediaDrivenBy: aMediaControlsFactoryBlock [

AssertionChecker
enforce: [ resourceLocator canLookupResources ]
because: 'Missing location resolution.'.
handlerFactory := [ HypermediaDrivenRESTfulRequestHandler
resourceLocator: resourceLocator
paginationPolicy: paginationPolicyFactory
decodingRules: decodingRules
encodingRules: encodingRules
calculateEntityTagsWith: entityTagFactoryBinding content
cachingDirectives: cachingDirectives
allowedLanguageTags: allowedLanguageTags
drivenBy: [ :builder :resource :requestContext :resourceLocation |
builder addAsSelfLink: resourceLocation.
aMediaControlsFactoryBlock
cull: builder
cull: resource
cull: requestContext
cull: resourceLocation.
builder build
]
handleErrorsWith: exceptionHandler
]
AssertionChecker
enforce: [ resourceLocator canLookupResources ] because: 'Missing location resolution.';
enforce: [ encodingRules isEmpty ]
because: 'Encoding rules needs to be configured after hypermedia'.
requestHandlerClass := HypermediaDrivenRESTfulRequestHandler.
requestHandlerFactory := [
requestHandlerClass
resourceLocator: resourceLocator
paginationPolicy: paginationPolicyFactory
decodingRules: decodingRules
encodingRules: encodingRules
calculateEntityTagsWith: entityTagFactoryBinding content
cachingDirectives: cachingDirectives
allowedLanguageTags: allowedLanguageTags
drivenBy: [ :builder :resource :requestContext :resourceLocation |
builder addAsSelfLink: resourceLocation.
aMediaControlsFactoryBlock
cull: builder
cull: resource
cull: requestContext
cull: resourceLocation.
builder build
]
handleErrorsWith: exceptionHandler
]
]

{ #category : 'building' }
RESTfulRequestHandlerBuilder >> build [

^ handlerFactory value
^ requestHandlerFactory value
]

{ #category : 'configuring' }
Expand Down Expand Up @@ -159,24 +163,27 @@ RESTfulRequestHandlerBuilder >> handling: anEndpoint locatingSubresourcesWith: a
{ #category : 'initialization' }
RESTfulRequestHandlerBuilder >> initialize [

super initialize.
decodingRules := Dictionary new.
encodingRules := Dictionary new.
entityTagFactoryBinding := Binding undefinedExplainedBy: 'Missing ETag calculation'.
cachingDirectives := #().
allowedLanguageTags := OrderedCollection new.
paginationPolicyFactory := [ :requestHandler | RESTfulControllerDoNotPaginateCollectionsPolicy for: requestHandler ].
exceptionHandler := RESTfulRequestExceptionHandler new.
handlerFactory := [ RESTfulRequestHandler
resourceLocator: resourceLocator
paginationPolicy: paginationPolicyFactory
decodingRules: decodingRules
encodingRules: encodingRules
calculateEntityTagsWith: entityTagFactoryBinding content
cachingDirectives: cachingDirectives
allowedLanguageTags: allowedLanguageTags
handleErrorsWith: exceptionHandler
]
super initialize.
decodingRules := Dictionary new.
encodingRules := Dictionary new.
entityTagFactoryBinding := Binding undefinedExplainedBy: 'Missing ETag calculation'.
cachingDirectives := #( ).
allowedLanguageTags := OrderedCollection new.
paginationPolicyFactory := [ :requestHandler |
RESTfulControllerDoNotPaginateCollectionsPolicy for: requestHandler ].
exceptionHandler := RESTfulRequestExceptionHandler new.
requestHandlerClass := RESTfulRequestHandler.
requestHandlerFactory := [
requestHandlerClass
resourceLocator: resourceLocator
paginationPolicy: paginationPolicyFactory
decodingRules: decodingRules
encodingRules: encodingRules
calculateEntityTagsWith: entityTagFactoryBinding content
cachingDirectives: cachingDirectives
allowedLanguageTags: allowedLanguageTags
handleErrorsWith: exceptionHandler
]
]

{ #category : 'private' }
Expand Down Expand Up @@ -227,43 +234,30 @@ RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeApplying: anEnc
{ #category : 'encoding' }
RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeToJsonApplying: aBlock [

self whenResponding: aMediaType encodeApplying: [ :resource :requestContext |
self
jsonFor: resource
within: requestContext
applying: aBlock
writingResourceWith: [ :writer |
writer for: ResourceCollection do: [ :mapping |
mapping
mapInstVar: #items;
mapAsHypermediaControls: [ :collection |
requestContext hypermediaControlsFor: collection items ]
].
writer nextPut: resource
]
]
self whenResponding: aMediaType encodeApplying: [ :resource :requestContext |
self
jsonFor: resource
within: requestContext
applying: aBlock
writingResourceWith: [ :writer |
requestHandlerClass encode: resource toJsonUsing: writer within: requestContext ]
]
]

{ #category : 'encoding' }
RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeToJsonApplying: aBlock as: schema [

self whenResponding: aMediaType encodeApplying: [ :resource :requestContext |
self
jsonFor: resource
within: requestContext
applying: aBlock
writingResourceWith: [ :writer |
writer
for: ResourceCollection do: [ :mapping |
( mapping mapInstVar: #items ) valueSchema: #ResourceCollectionItems.
mapping mapAsHypermediaControls: [ :collection |
requestContext hypermediaControlsFor: collection items ]
];
for: #ResourceCollectionItems customDo: [ :mapping | mapping listOfElementSchema: schema ].

[ writer nextPut: resource as: schema ]
unless: ( resource isA: ResourceCollection )
inWhichCase: [ writer nextPut: resource ]
]
]
self whenResponding: aMediaType encodeApplying: [ :resource :requestContext |
self
jsonFor: resource
within: requestContext
applying: aBlock
writingResourceWith: [ :writer |
requestHandlerClass
encode: resource
toJsonUsing: writer
as: schema
within: requestContext
]
]
]

0 comments on commit 0d6dfa1

Please sign in to comment.