Skip to content

Commit

Permalink
Merge pull request #3 from ba-st/collections
Browse files Browse the repository at this point in the history
Implement Collection Handling
  • Loading branch information
fortizpenaloza authored Oct 19, 2018
2 parents f665a05 + 6328f66 commit 39bd4b2
Show file tree
Hide file tree
Showing 8 changed files with 329 additions and 69 deletions.
56 changes: 56 additions & 0 deletions source/Stargate-Examples/Pet.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
"
I'm a toy abstraction used just as an example
"
Class {
#name : #Pet,
#superclass : #Object,
#instVars : [
'name',
'type',
'status'
],
#category : #'Stargate-Examples'
}

{ #category : #'instance creation' }
Pet class >> named: aName ofType: aPetType [

^ self named: aName ofType: aPetType withStatus: 'new'
]

{ #category : #'instance creation' }
Pet class >> named: aName ofType: aPetType withStatus: status [

^ self new initializeNamed: aName ofType: aPetType withStatus: status
]

{ #category : #initialization }
Pet >> initializeNamed: aName ofType: aPetType withStatus: aStatus [

name := aName.
type := aPetType.
status := aStatus
]

{ #category : #accessing }
Pet >> name [
^ name
]

{ #category : #accessing }
Pet >> status [
^ status
]

{ #category : #updating }
Pet >> synchronizeWith: aPet [

name := aPet name.
type := aPet type.
status := aPet status
]

{ #category : #accessing }
Pet >> type [
^ type
]
30 changes: 23 additions & 7 deletions source/Stargate-Examples/PetsRESTfulWebService.class.st
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"
I'm an example RESTful Web Service implementing Pet resource management
"
Class {
#name : #PetsRESTfulWebService,
#superclass : #RESTfulWebService,
Expand All @@ -13,11 +16,14 @@ Class {
PetsRESTfulWebService >> createPetBasedOn: anHttpRequest within: aContext [

^ self
withCreatedResourceDo: [ :pet |
pets add: pet.
pet at: #status put: 'new'.
petById at: nextId put: pet.
nextId := nextId + 1 ]
withCreatedResourceDo: [ :resource |
| newPet |

newPet := Pet named: resource name ofType: resource type.
pets add: newPet.
petById at: nextId put: newPet.
nextId := nextId + 1.
newPet ]
decodedUsing: self specification petMappingKey
basedOn: anHttpRequest
within: aContext
Expand All @@ -43,6 +49,16 @@ PetsRESTfulWebService >> getPetBasedOn: anHttpRequest within: aContext [
within: aContext
]

{ #category : #API }
PetsRESTfulWebService >> getPetsBasedOn: anHttpRequest within: aContext [

^ self
get: [ self pets ]
asCollectionEncodedUsing: self specification petsMappingKey
basedOn: anHttpRequest
within: aContext
]

{ #category : #initialization }
PetsRESTfulWebService >> initialize [

Expand Down Expand Up @@ -89,11 +105,11 @@ PetsRESTfulWebService >> updatePetStatusBasedOn: anHttpRequest within: aContext

resource := self
decode: anHttpRequest contents
at: #pets
at: self specification petMappingKey
from: anHttpRequest contentType
within: aContext.
pet := self petIdentifiedUsing: anHttpRequest.
pet at: #status put: (resource at: #status).
pet synchronizeWith: (Pet named: (resource at: #name ifAbsent: [ pet name ]) ofType: (resource at: #type ifAbsent: [ pet type ]) withStatus: (resource at: #status ifAbsent: [ pet status ])).
pet ]
encodedUsing: self specification petMappingKey
basedOn: anHttpRequest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,39 @@ PetsRESTfulWebServiceSpecification >> addJsonEncoderVersion1dot0dot0MappingIn: a
using: [ :pet :context |
String
streamContents: [ :stream |
(HypermediaAwareJSONWriter on: stream)
mediaControls: (context objectUnder: #mediaControls ifNone: [ #() ]) asDictionary;
(NeoJSONWriter on: stream)
for: Pet
do: [ :mapping |
mapping
mapInstVars;
mapHypermediaControlsIn: context ];
nextPut: pet ] ];
addRuleToEncode: self petMappingKey
to: self petSummaryVersion1dot0dot0MediaType
using: [ :pet :context |
String
streamContents: [ :stream |
(HypermediaAwareJSONWriter on: stream)
mediaControls: (context objectUnder: #mediaControls ifNone: [ #() ]) asDictionary;
nextPut: {('name' -> pet name)} asDictionary ] ]
(NeoJSONWriter on: stream)
for: Pet
do: [ :mapping |
mapping
mapInstVar: #name;
mapHypermediaControlsIn: context ];
nextPut: pet ] ];
addDefaultRuleToEncode: self petsMappingKey
to: self petSummaryVersion1dot0dot0MediaType
using: [ :pets :context |
String
streamContents: [ :stream |
(NeoJSONWriter on: stream)
for: Pet
do: [ :mapping |
mapping
mapInstVar: #name;
mapAsHypermediaControls: [ :pet | context hypermediaControlsFor: pet ] ];
nextPut:
{('items' -> pets).
('links' -> context hypermediaControls asDictionary)} asDictionary ] ]
]

{ #category : #routes }
Expand Down Expand Up @@ -78,7 +100,7 @@ PetsRESTfulWebServiceSpecification >> identifierKey [
{ #category : #accessing }
PetsRESTfulWebServiceSpecification >> petMappingKey [

^ #pets
^ #pet
]

{ #category : #'accessing - media types' }
Expand All @@ -93,6 +115,12 @@ PetsRESTfulWebServiceSpecification >> petVersion1dot0dot0MediaType [
^ 'application/vnd.stargate.pet+json;version=1.0.0' asZnMimeType
]

{ #category : #accessing }
PetsRESTfulWebServiceSpecification >> petsMappingKey [

^ #pets
]

{ #category : #routes }
PetsRESTfulWebServiceSpecification >> updatePetRoute [

Expand Down
136 changes: 130 additions & 6 deletions source/Stargate-REST-API-Tests/PetsRESTfulWebServiceTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,68 @@ Class {
#category : #'Stargate-REST-API-Tests'
}

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> baseUrl [

^ 'https://pets.example.com' asZnUrl
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> petsUrl [

^ self baseUrl / '/pets/' asZnUrl
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> requestToCreatePetFrom: aJson [

^ (ZnRequest post: 'http://BASE_URL/pets')
^ (ZnRequest post: self petsUrl)
entity: (ZnEntity with: aJson type: webService specification petVersion1dot0dot0MediaType);
yourself
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> requestToDeletePetIdentifiedBy: anIdentifier [

^ TeaRequest fromZnRequest: (ZnRequest delete: ('http://BASE_URL/pets/<1p>' expandMacrosWith: anIdentifier)) pathParams: {(#identifier -> anIdentifier)} asDictionary
^ TeaRequest fromZnRequest: (ZnRequest delete: (self urlForPetIdentifiedBy: anIdentifier)) pathParams: {(#identifier -> anIdentifier)} asDictionary
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> requestToGetPetIdentifiedBy: anIdentifier accepting: anAcceptHeader [

^ TeaRequest
fromZnRequest:
((ZnRequest get: ('http://BASE_URL/pets/<1p>' expandMacrosWith: anIdentifier))
((ZnRequest get: (self urlForPetIdentifiedBy: anIdentifier))
setAccept: anAcceptHeader;
yourself)
pathParams: {(#identifier -> anIdentifier)} asDictionary
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> requestToGetPetsAccepting: anAcceptHeader [

^ (ZnRequest get: self petsUrl)
setAccept: anAcceptHeader;
yourself
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> requestToUpdatePetIdentifiedBy: anIdentifier nameTo: aName [

^ TeaRequest
fromZnRequest:
((ZnRequest patch: (self urlForPetIdentifiedBy: anIdentifier))
entity: (ZnEntity with: ('{"name":"<1s>"}' expandMacrosWith: aName) type: webService specification petVersion1dot0dot0MediaType);
yourself)
pathParams: {(#identifier -> anIdentifier)} asDictionary
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> requestToUpdatePetIdentifiedBy: anIdentifier statusTo: aStatus [

^ TeaRequest
fromZnRequest:
((ZnRequest patch: ('http://BASE_URL/pets/<1p>' expandMacrosWith: anIdentifier))
((ZnRequest patch: (self urlForPetIdentifiedBy: anIdentifier))
entity: (ZnEntity with: ('{"status":"<1s>"}' expandMacrosWith: aStatus) type: webService specification petVersion1dot0dot0MediaType);
yourself)
pathParams: {(#identifier -> anIdentifier)} asDictionary
Expand All @@ -47,7 +78,7 @@ PetsRESTfulWebServiceTest >> requestToUpdatePetIdentifiedBy: anIdentifier status
PetsRESTfulWebServiceTest >> setUp [

webService := PetsRESTfulWebService new.
webService serverUrl: 'https://pets.example.com' asZnUrl
webService serverUrl: self baseUrl asZnUrl
]

{ #category : #tests }
Expand Down Expand Up @@ -140,7 +171,63 @@ PetsRESTfulWebServiceTest >> testGetPetSummaryJustCreated [
self
assert: json name equals: 'Firulais';
assert: json links self equals: 'https://pets.example.com/pets/1';
assert: json type isNil ]
assert: json type isNil;
assert: json status isNil ]
]

{ #category : #tests }
PetsRESTfulWebServiceTest >> testGetPets [

| response |

self assert: webService pets isEmpty.

response := webService getPetsBasedOn: (self requestToGetPetsAccepting: '*/*') within: HttpRequestContext new.

self
assert: response isSuccess;
assert: response status equals: 200;
assert: response contentType asZnMimeType equals: webService specification petSummaryVersion1dot0dot0MediaType.

self
withJsonFromContentsIn: response
do: [ :json |
self
assert: json items isEmpty;
assert: json links self equals: 'https://pets.example.com/pets/' ]
]

{ #category : #tests }
PetsRESTfulWebServiceTest >> testGetPetsNotEmpty [

| response |

self assert: webService pets isEmpty.

webService createPetBasedOn: (self requestToCreatePetFrom: '{"name":"Firulais","type":"dog"}') within: HttpRequestContext new.

self assert: webService pets notEmpty.

response := webService getPetsBasedOn: (self requestToGetPetsAccepting: '*/*') within: HttpRequestContext new.

self
assert: response isSuccess;
assert: response status equals: 200;
assert: response contentType asZnMimeType equals: webService specification petSummaryVersion1dot0dot0MediaType.

self
withJsonFromContentsIn: response
do: [ :json |
| dogSummary |

self
assert: json links self equals: 'https://pets.example.com/pets/';
assert: json items size equals: 1.
dogSummary := json items first.
self
assert: dogSummary name equals: 'Firulais';
assert: dogSummary links self equals: 'https://pets.example.com/pets/1';
assert: dogSummary type isNil ]
]

{ #category : #tests }
Expand All @@ -161,6 +248,37 @@ PetsRESTfulWebServiceTest >> testPetCreation [
assert: webService pets first name equals: 'Firulais'
]

{ #category : #tests }
PetsRESTfulWebServiceTest >> testUpdatePetName [

| response |

self assert: webService pets isEmpty.

self assert: (webService createPetBasedOn: (self requestToCreatePetFrom: '{"name":"Firulais","type":"dog"}') within: HttpRequestContext new) isSuccess.

self assert: webService pets first name equals: 'Firulais'.

response := webService updatePetStatusBasedOn: (self requestToUpdatePetIdentifiedBy: 1 nameTo: 'Mendieta') within: HttpRequestContext new.

self
assert: response isSuccess;
assert: response status equals: 200;
assert: response hasEntity;
assert: webService pets size equals: 1;
assert: webService pets first name equals: 'Mendieta';
assert: webService pets first status equals: 'new'.

self
withJsonFromContentsIn: response
do: [ :json |
self
assert: json name equals: 'Mendieta';
assert: json type equals: 'dog';
assert: json status equals: 'new';
assert: json links self equals: 'https://pets.example.com/pets/1' ]
]

{ #category : #tests }
PetsRESTfulWebServiceTest >> testUpdatePetStatus [

Expand Down Expand Up @@ -194,6 +312,12 @@ PetsRESTfulWebServiceTest >> testUpdatePetStatus [
assert: json links self equals: 'https://pets.example.com/pets/1' ]
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> urlForPetIdentifiedBy: anIdentifier [

^ self petsUrl / anIdentifier printString asZnUrl
]

{ #category : #'private - support' }
PetsRESTfulWebServiceTest >> withJsonFromContentsIn: httpResponse do: aBlock [

Expand Down
Loading

0 comments on commit 39bd4b2

Please sign in to comment.