From f52538e7b19741d3b86ea3c70c5842963822ed1c Mon Sep 17 00:00:00 2001 From: Gabriel Cotelli Date: Wed, 22 Nov 2023 11:40:32 -0300 Subject: [PATCH 1/2] Improve CORS handling for requests responded with errors Use the available CORS configuration to set the expected headers in case the HTTPClientError handler kicked-in. Fix the global error handler configured in StargateApplication to pay attention to CORS. Improve tests related to CORS. Fixes #180 --- .../StargateApplication.class.st | 83 +++--- source/Stargate-API-Skeleton/package.st | 2 +- .../ErroneousAPITest.class.st | 236 ++++++++++++++++++ .../ErroneousRESTfulController.class.st | 44 ++++ .../PetStoreAPITest.class.st | 163 ++++++++---- .../InMemoryPetOrderRepository.class.st | 28 ++- .../InMemoryPetRepository.class.st | 28 ++- source/Stargate-Examples/Pet.class.st | 22 +- source/Stargate-Examples/PetOrder.class.st | 16 +- .../PetOrdersRESTfulController.class.st | 84 ++++--- .../PetStoreApplication.class.st | 22 +- .../PetsRESTfulController.class.st | 52 ++-- ...outhAmericanCurrenciesApplication.class.st | 18 +- ...ericanCurrenciesRESTfulController.class.st | 42 ++-- .../StargateCurrency.class.st | 18 +- source/Stargate-Examples/package.st | 2 +- .../HTTPMetrics.class.st | 51 ++-- source/Stargate-Metrics-HTTP/package.st | 2 +- .../AllowAnyOriginPolicy.class.st | 10 +- .../Stargate-Model/AllowOriginPolicy.class.st | 10 +- .../AllowSpecifiedOriginsPolicy.class.st | 19 +- .../AuthenticationFilter.class.st | 24 +- .../CachingDirectivesBuilder.class.st | 58 ++--- ...sourceSharingActualRequestHandler.class.st | 18 +- ...haringActualRequestHandlerBuilder.class.st | 20 +- .../CrossOriginResourceSharingFilter.class.st | 20 +- ...riginResourceSharingFilterBuilder.class.st | 43 ++-- ...CrossOriginResourceSharingHandler.class.st | 16 +- ...inResourceSharingPreflightHandler.class.st | 24 +- ...rceSharingPreflightHandlerBuilder.class.st | 26 +- ...ourceSharingRequestHandlerBuilder.class.st | 10 +- .../Stargate-Model/EntityTagHasher.class.st | 14 +- .../HTTPBasedRESTfulAPI.class.st | 101 ++++---- .../HttpRequestContext.class.st | 42 ++-- ...rmediaDrivenRESTfulRequestHandler.class.st | 20 +- .../JWTBearerAuthenticationFilter.class.st | 20 +- .../MediaControlsBuilder.class.st | 22 +- .../Stargate-Model/OperationalPlugin.class.st | 36 +-- ...erationalPluginsRESTfulController.class.st | 38 +-- .../OperationsRESTfulController.class.st | 24 +- .../PaginationSpecification.class.st | 20 +- .../QualifiedLanguageRange.class.st | 18 +- ...RESTfulControllerAcceptNegotiator.class.st | 38 +-- ...lerDoNotPaginateCollectionsPolicy.class.st | 18 +- ...erDoNotRespondCreatedEntityPolicy.class.st | 14 +- ...ntrollerPaginateCollectionsPolicy.class.st | 20 +- ...RESTfulControllerPaginationPolicy.class.st | 14 +- ...lControllerResourceCreationPolicy.class.st | 10 +- ...trollerRespondCreatedEntityPolicy.class.st | 14 +- .../RESTfulRequestExceptionHandler.class.st | 30 +-- .../RESTfulRequestHandler.class.st | 10 +- .../RESTfulRequestHandlerBehavior.class.st | 66 ++--- .../RESTfulRequestHandlerBuilder.class.st | 54 ++-- .../ReflectiveRoutesConfigurator.class.st | 14 +- .../ResourceCollection.class.st | 14 +- .../ResourceEncodingRule.class.st | 14 +- .../Stargate-Model/ResourceLocator.class.st | 34 +-- .../ResourceLocatorBehavior.class.st | 26 +- .../ResourceRESTfulController.class.st | 16 +- .../Stargate-Model/RouteConfigurator.class.st | 18 +- .../RouteSpecification.class.st | 24 +- .../SingleResourceRESTfulController.class.st | 24 +- .../SubresourceLocator.class.st | 32 +-- source/Stargate-Model/WebOrigin.class.st | 26 +- .../ZnAuthenticationFilter.class.st | 22 +- source/Stargate-Model/package.st | 2 +- .../HTTPBasedRESTfulAPITest.class.st | 47 ++-- .../OperationalPluginAPITest.class.st | 29 +-- ...tionalPluginRESTfulControllerTest.class.st | 15 +- .../ResourceRESTfulControllerTest.class.st | 25 +- ...ngleResourceRESTfulControllerTest.class.st | 41 +-- source/Stargate-SUnit-Model/package.st | 2 +- 72 files changed, 1380 insertions(+), 899 deletions(-) create mode 100644 source/Stargate-Examples-Tests/ErroneousAPITest.class.st create mode 100644 source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st diff --git a/source/Stargate-API-Skeleton/StargateApplication.class.st b/source/Stargate-API-Skeleton/StargateApplication.class.st index d7951e8..cd73775 100644 --- a/source/Stargate-API-Skeleton/StargateApplication.class.st +++ b/source/Stargate-API-Skeleton/StargateApplication.class.st @@ -1,22 +1,23 @@ Class { - #name : #StargateApplication, - #superclass : #LaunchpadApplication, + #name : 'StargateApplication', + #superclass : 'LaunchpadApplication', #instVars : [ 'apiOptional' ], #classInstVars : [ 'Version' ], - #category : #'Stargate-API-Skeleton' + #category : 'Stargate-API-Skeleton', + #package : 'Stargate-API-Skeleton' } -{ #category : #accessing } +{ #category : 'accessing' } StargateApplication class >> configurationParameters [ ^ self stargateConfigurationParameters ] -{ #category : #private } +{ #category : 'private' } StargateApplication class >> fileReferenceToDumpStackTrace [ | logsDirectory stackTraceDumpFile | @@ -46,44 +47,44 @@ StargateApplication class >> fileReferenceToDumpStackTrace [ ^ stackTraceDumpFile ] -{ #category : #initialization } +{ #category : 'initialization' } StargateApplication class >> initializeVersion [ Version := VersionFromRepositoryResolver new valueFor: self projectName ] -{ #category : #testing } +{ #category : 'testing' } StargateApplication class >> isAbstract [ ^ self = StargateApplication ] -{ #category : #private } +{ #category : 'private' } StargateApplication class >> logsDirectory [ ^ ( FileLocator workingDirectory / 'logs' ) ensureCreateDirectory ] -{ #category : #private } +{ #category : 'private' } StargateApplication class >> projectName [ ^ self subclassResponsibility ] -{ #category : #private } +{ #category : 'private' } StargateApplication class >> sectionsForStargateConfiguration [ ^ #('Stargate') ] -{ #category : #private } +{ #category : 'private' } StargateApplication class >> stackTraceDumpExtension [ ^ 'dump' ] -{ #category : #private } +{ #category : 'private' } StargateApplication class >> stargateConfigurationParameters [ ^ Array @@ -101,13 +102,13 @@ StargateApplication class >> stargateConfigurationParameters [ convertingWith: #asByteArray ) asSensitive ] -{ #category : #accessing } +{ #category : 'accessing' } StargateApplication class >> version [ ^ Version ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> apiConfiguration [ ^ Array with: #serverUrl -> self stargateConfiguration publicURL @@ -116,7 +117,7 @@ StargateApplication >> apiConfiguration [ with: #operations -> self operationsConfiguration ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> applicationConfigurationConfiguration [ ^ Dictionary new @@ -126,7 +127,7 @@ StargateApplication >> applicationConfigurationConfiguration [ yourself ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> applicationControlCommandsToEnable [ "This method must return an array of application control command names to be enabled" @@ -134,7 +135,7 @@ StargateApplication >> applicationControlCommandsToEnable [ ^ #( ) ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> applicationControlConfiguration [ ^ Dictionary new @@ -143,7 +144,7 @@ StargateApplication >> applicationControlConfiguration [ yourself ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> applicationInfoConfiguration [ ^ Dictionary new @@ -152,7 +153,7 @@ StargateApplication >> applicationInfoConfiguration [ yourself ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> authAlgorithm [ "The signing algorithm identifier as defined in https://datatracker.ietf.org/doc/html/rfc7518#section-3.1. Used for securing operational plugins, by default HMAC using SHA-256" @@ -160,7 +161,7 @@ StargateApplication >> authAlgorithm [ ^ 'HS256' ] -{ #category : #'private - activation/deactivation' } +{ #category : 'private - activation/deactivation' } StargateApplication >> basicStartWithin: context [ | api | @@ -173,41 +174,43 @@ StargateApplication >> basicStartWithin: context [ apiOptional := Optional containing: api ] -{ #category : #'private - activation/deactivation' } +{ #category : 'private - activation/deactivation' } StargateApplication >> basicStop [ apiOptional withContentDo: [ :api | api stop ]. super basicStop ] -{ #category : #'private - activation/deactivation' } +{ #category : 'private - activation/deactivation' } StargateApplication >> configureGlobalErrorHandlerIn: api [ - + [ LogRecord emitInfo: 'Configuring error handlers' during: [ api - on: Error addErrorHandler: [ :error | + on: Error addErrorHandler: [ :error :request | + | response | + LogRecord emitError: ( 'Unexpected error: "<1s>"' expandMacrosWith: error messageText ). self stackTraceDumper dumpStackTraceFor: error. - TeaResponse serverError - body: error messageText; - yourself + response := ZnResponse serverError: error messageText. + api applyCrossSharingResourceConfigurationTo: response accordingTo: request. + response ]; on: Exit addErrorHandler: [ :exit | - exit isSuccess then: [ self stop ]. - exit pass - ] + exit isSuccess then: [ self stop ]. + exit pass + ] ] ] unless: self isDebugModeEnabled ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> controllersToInstall [ ^ self subclassResponsibility ] -{ #category : #'private - activation/deactivation' } +{ #category : 'private - activation/deactivation' } StargateApplication >> createAPI [ | api | @@ -218,14 +221,14 @@ StargateApplication >> createAPI [ ^ api ] -{ #category : #initialization } +{ #category : 'initialization' } StargateApplication >> initialize [ super initialize. apiOptional := Optional unused ] -{ #category : #'private - activation/deactivation' } +{ #category : 'private - activation/deactivation' } StargateApplication >> installAndStart: api [ LogRecord @@ -233,7 +236,7 @@ StargateApplication >> installAndStart: api [ emitInfo: 'Starting API' during: [ api start ] ] -{ #category : #'private - activation/deactivation' } +{ #category : 'private - activation/deactivation' } StargateApplication >> logAPIVersion [ BasicApplicationInformationProvider new applicationNamed: self class commandName @@ -242,7 +245,7 @@ StargateApplication >> logAPIVersion [ LogRecord emitInfo: ( 'API Version: <1s>' expandMacrosWith: self class version ) ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> loggersConfiguration [ ^ Dictionary new @@ -250,7 +253,7 @@ StargateApplication >> loggersConfiguration [ yourself ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> metricsConfiguration [ ^ Dictionary new @@ -262,7 +265,7 @@ StargateApplication >> metricsConfiguration [ yourself ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> operationsConfiguration [ ^ Dictionary new @@ -277,7 +280,7 @@ StargateApplication >> operationsConfiguration [ yourself ] -{ #category : #'error handling' } +{ #category : 'error handling' } StargateApplication >> stackTraceDumper [ ^ StackTraceTextDumper on: [ :dumpAction | @@ -286,7 +289,7 @@ StargateApplication >> stackTraceDumper [ ] ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } StargateApplication >> stargateConfiguration [ ^ self configuration stargate diff --git a/source/Stargate-API-Skeleton/package.st b/source/Stargate-API-Skeleton/package.st index 4ad11d8..1b89856 100644 --- a/source/Stargate-API-Skeleton/package.st +++ b/source/Stargate-API-Skeleton/package.st @@ -1 +1 @@ -Package { #name : #'Stargate-API-Skeleton' } +Package { #name : 'Stargate-API-Skeleton' } diff --git a/source/Stargate-Examples-Tests/ErroneousAPITest.class.st b/source/Stargate-Examples-Tests/ErroneousAPITest.class.st new file mode 100644 index 0000000..c12495a --- /dev/null +++ b/source/Stargate-Examples-Tests/ErroneousAPITest.class.st @@ -0,0 +1,236 @@ +Class { + #name : 'ErroneousAPITest', + #superclass : 'HTTPBasedRESTfulAPITest', + #instVars : [ + 'controller' + ], + #category : 'Stargate-Examples-Tests-Server-Errors', + #package : 'Stargate-Examples-Tests', + #tag : 'Server-Errors' +} + +{ #category : 'asserting' } +ErroneousAPITest >> assert: aResponse canBeSharedWithRequestsFrom: anOriginLocation [ + + self + assert: ( aResponse headers at: 'Access-Control-Allow-Origin' ) + equals: anOriginLocation asWebOrigin asString +] + +{ #category : 'private' } +ErroneousAPITest >> controllersToInstall [ + + ^ { controller } +] + +{ #category : 'running' } +ErroneousAPITest >> globalErrorHandler [ + + ^ [ :error :request | + | response | + + response := ZnResponse serverError: error messageText. + api applyCrossSharingResourceConfigurationTo: response accordingTo: request. + response + ] +] + +{ #category : 'running' } +ErroneousAPITest >> setUpAPI [ + + controller := ErroneousRESTfulController new. + super setUpAPI +] + +{ #category : 'tests' } +ErroneousAPITest >> testCORSAllowingAnyOrigin [ + + | response | + + api allowCrossOriginSharingApplying: [ :cors | cors allowAnyOrigin ]. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. + self + assert: response isNoContent; + assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*'; + assert: ( response headers at: 'Access-Control-Allow-Headers' ) equals: 'Content-Type'; + assert: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'GET'. + + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. + + self + assert: response code equals: 500; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*' +] + +{ #category : 'tests' } +ErroneousAPITest >> testCORSAllowingExactlyOneOrigin [ + + | response | + + api allowCrossOriginSharingApplying: [ :cors | cors allowOnlyFrom: { self baseUrl } ]. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. + + self + assert: response isNoContent; + assert: response canBeSharedWithRequestsFrom: self baseUrl; + assert: ( response headers at: 'Access-Control-Allow-Headers' ) equals: 'Content-Type'; + assert: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Origin'; + assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'GET'. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. + + self + assert: response code equals: 500; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Origin'; + assert: response canBeSharedWithRequestsFrom: self baseUrl +] + +{ #category : 'tests' } +ErroneousAPITest >> testCORSAllowingMoreThanOneOrigin [ + + | response | + + api allowCrossOriginSharingApplying: [ :cors | + cors allowOnlyFrom: { + self baseUrl. + 'http://google.com/' asUrl } + ]. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. + + self + assert: response isNoContent; + assert: response canBeSharedWithRequestsFrom: self baseUrl; + assert: ( response headers at: 'Access-Control-Allow-Headers' ) equals: 'Content-Type'; + assert: response varyHeaderNames includes: 'Origin'; + assert: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'GET'. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. + + self + assert: response code equals: 500; + assert: response varyHeaderNames includes: 'Origin'; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + assert: response canBeSharedWithRequestsFrom: self baseUrl +] + +{ #category : 'tests' } +ErroneousAPITest >> testCORSOptionalHeaders [ + + | response | + + api allowCrossOriginSharingApplying: [ :cors | + cors + allowAnyOrigin; + allowCredentials; + expireIn: 600 seconds; + expose: #( 'Authorization' 'X-Custom' ) + ]. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. + + self + assert: response isNoContent; + assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*'; + assert: ( response headers at: 'Access-Control-Allow-Headers' ) equals: 'Content-Type'; + assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'GET'; + assert: ( response headers at: 'Access-Control-Expose-Headers' ) + equals: 'Authorization, X-Custom'; + assert: ( response headers at: 'Access-Control-Allow-Credentials' ) equals: 'true'; + assert: ( response headers at: 'Access-Control-Max-Age' ) equals: '600'; + assert: response varyHeaderNames includes: 'Access-Control-Allow-Headers'. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. + + self + assert: response code equals: 500; + assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*'; + should: [ response headers at: 'Access-Control-Allow-Headers' ] raise: KeyNotFound; + should: [ response headers at: 'Access-Control-Allow-Methods' ] raise: KeyNotFound; + assert: ( response headers at: 'Access-Control-Expose-Headers' ) + equals: 'Authorization, X-Custom'; + assert: ( response headers at: 'Access-Control-Allow-Credentials' ) equals: 'true'; + should: [ response headers at: 'Access-Control-Max-Age' ] raise: KeyNotFound; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers' +] + +{ #category : 'tests' } +ErroneousAPITest >> testCORSRespondWithEmptyHeadersIfOriginNotAllowed [ + + | response | + + api allowCrossOriginSharingApplying: [ :cors | cors allowOnlyFrom: { 'https://google.com' asUrl } ]. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. + + self + assert: response isNoContent; + should: [ response headers at: 'Access-Control-Allow-Origin' ] raise: KeyNotFound; + should: [ response headers at: 'Access-Control-Allow-Headers' ] raise: KeyNotFound; + should: [ response headers at: 'Access-Control-Allow-Methods' ] raise: KeyNotFound. + + response := self newClient + url: self baseUrl / 'errors' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. + + self + assert: response code equals: 500; + assert: response varyHeaderNames isEmpty; + should: [ response headers at: 'Access-Control-Allow-Origin' ] raise: KeyNotFound +] diff --git a/source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st b/source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st new file mode 100644 index 0000000..4e27ce1 --- /dev/null +++ b/source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st @@ -0,0 +1,44 @@ +Class { + #name : 'ErroneousRESTfulController', + #superclass : 'SingleResourceRESTfulController', + #instVars : [ + 'requestHandler' + ], + #category : 'Stargate-Examples-Tests-Server-Errors', + #package : 'Stargate-Examples-Tests', + #tag : 'Server-Errors' +} + +{ #category : 'routes' } +ErroneousRESTfulController >> declareGetErroneousRoute [ + + ^ RouteSpecification + handling: #GET + at: self endpoint + evaluating: [ :httpRequest :requestContext | Error signal: 'Server error' ] +] + +{ #category : 'initialization' } +ErroneousRESTfulController >> initialize [ + + super initialize. + requestHandler := RESTfulRequestHandlerBuilder new + handling: 'errors' + extractingIdentifierWith: [ :httpRequest | self identifierIn: httpRequest ]; + whenResponding: ZnMimeType applicationJson + encodeToJsonApplying: [ :resource :requestContext :writer | ]; + createEntityTagHashingEncodedResource; + build +] + +{ #category : 'private' } +ErroneousRESTfulController >> requestHandler [ + + ^ requestHandler +] + +{ #category : 'private' } +ErroneousRESTfulController >> typeIdConstraint [ + + ^ IsObject +] diff --git a/source/Stargate-Examples-Tests/PetStoreAPITest.class.st b/source/Stargate-Examples-Tests/PetStoreAPITest.class.st index 7a81fa2..c8198b5 100644 --- a/source/Stargate-Examples-Tests/PetStoreAPITest.class.st +++ b/source/Stargate-Examples-Tests/PetStoreAPITest.class.st @@ -64,11 +64,11 @@ PetStoreAPITest >> testCORSAllowingAnyOrigin [ api allowCrossOriginSharingApplying: [ :cors | cors allowAnyOrigin ]. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; - options; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. self assert: response isNoContent; @@ -78,12 +78,24 @@ PetStoreAPITest >> testCORSAllowingAnyOrigin [ assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'POST, GET'. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - get; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + get; + response. + + self + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*'. + + response := self newClient + url: self baseUrl / 'pets' / '404' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. self + assert: response isNotFound; deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*' ] @@ -93,14 +105,14 @@ PetStoreAPITest >> testCORSAllowingExactlyOneOrigin [ | response | - api allowCrossOriginSharingApplying: [ :cors | cors allowOnlyFrom: {self baseUrl} ]. + api allowCrossOriginSharingApplying: [ :cors | cors allowOnlyFrom: { self baseUrl } ]. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; - options; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. self assert: response isNoContent; @@ -111,12 +123,25 @@ PetStoreAPITest >> testCORSAllowingExactlyOneOrigin [ assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'POST, GET'. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - get; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + get; + response. + + self + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Origin'; + assert: response canBeSharedWithRequestsFrom: self baseUrl. + + response := self newClient + url: self baseUrl / 'pets' / '404' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. self + assert: response isNotFound; deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; deny: response varyHeaderNames includes: 'Access-Control-Allow-Origin'; assert: response canBeSharedWithRequestsFrom: self baseUrl @@ -127,20 +152,18 @@ PetStoreAPITest >> testCORSAllowingMoreThanOneOrigin [ | response | - api - allowCrossOriginSharingApplying: [ :cors | - cors - allowOnlyFrom: - {self baseUrl. - 'http://google.com/' asUrl} - ]. + api allowCrossOriginSharingApplying: [ :cors | + cors allowOnlyFrom: { + self baseUrl. + 'http://google.com/' asUrl } + ]. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; - options; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. self assert: response isNoContent; @@ -151,15 +174,28 @@ PetStoreAPITest >> testCORSAllowingMoreThanOneOrigin [ assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'POST, GET'. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - get; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + get; + response. + + self + assert: response varyHeaderNames includes: 'Origin'; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; + assert: response canBeSharedWithRequestsFrom: self baseUrl. + + response := self newClient + url: self baseUrl / 'pets' / '404' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. self + assert: response isNotFound; assert: response varyHeaderNames includes: 'Origin'; deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'; - assert: response canBeSharedWithRequestsFrom: self baseUrl + assert: response canBeSharedWithRequestsFrom: self baseUrl ] { #category : 'tests - CORS' } @@ -167,21 +203,20 @@ PetStoreAPITest >> testCORSOptionalHeaders [ | response | - api - allowCrossOriginSharingApplying: [ :cors | - cors - allowAnyOrigin; - allowCredentials; - expireIn: 600 seconds; - expose: #('Authorization' 'X-Custom') - ]. + api allowCrossOriginSharingApplying: [ :cors | + cors + allowAnyOrigin; + allowCredentials; + expireIn: 600 seconds; + expose: #( 'Authorization' 'X-Custom' ) + ]. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; - options; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; + options; + response. self assert: response isNoContent; @@ -189,23 +224,41 @@ PetStoreAPITest >> testCORSOptionalHeaders [ assert: ( response headers at: 'Access-Control-Allow-Headers' ) equals: 'Content-Type'; assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'POST, GET'; assert: ( response headers at: 'Access-Control-Expose-Headers' ) - equals: 'Authorization, X-Custom'; + equals: 'Authorization, X-Custom'; assert: ( response headers at: 'Access-Control-Allow-Credentials' ) equals: 'true'; assert: ( response headers at: 'Access-Control-Max-Age' ) equals: '600'; assert: response varyHeaderNames includes: 'Access-Control-Allow-Headers'. response := self newClient - url: self baseUrl / 'pets' asUrl; - headerAt: 'Origin' put: self baseUrl printString; - get; - response. + url: self baseUrl / 'pets' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + get; + response. + + self + assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*'; + should: [ response headers at: 'Access-Control-Allow-Headers' ] raise: KeyNotFound; + should: [ response headers at: 'Access-Control-Allow-Methods' ] raise: KeyNotFound; + assert: ( response headers at: 'Access-Control-Expose-Headers' ) + equals: 'Authorization, X-Custom'; + assert: ( response headers at: 'Access-Control-Allow-Credentials' ) equals: 'true'; + should: [ response headers at: 'Access-Control-Max-Age' ] raise: KeyNotFound; + deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers'. + + response := self newClient + url: self baseUrl / 'pets' / '404' asUrl; + headerAt: 'Origin' put: self baseUrl printString; + enforceHttpSuccess: false; + get; + response. self + assert: response isNotFound; assert: ( response headers at: 'Access-Control-Allow-Origin' ) equals: '*'; should: [ response headers at: 'Access-Control-Allow-Headers' ] raise: KeyNotFound; should: [ response headers at: 'Access-Control-Allow-Methods' ] raise: KeyNotFound; assert: ( response headers at: 'Access-Control-Expose-Headers' ) - equals: 'Authorization, X-Custom'; + equals: 'Authorization, X-Custom'; assert: ( response headers at: 'Access-Control-Allow-Credentials' ) equals: 'true'; should: [ response headers at: 'Access-Control-Max-Age' ] raise: KeyNotFound; deny: response varyHeaderNames includes: 'Access-Control-Allow-Headers' diff --git a/source/Stargate-Examples/InMemoryPetOrderRepository.class.st b/source/Stargate-Examples/InMemoryPetOrderRepository.class.st index 4e14d69..04ac522 100644 --- a/source/Stargate-Examples/InMemoryPetOrderRepository.class.st +++ b/source/Stargate-Examples/InMemoryPetOrderRepository.class.st @@ -1,6 +1,6 @@ Class { - #name : #InMemoryPetOrderRepository, - #superclass : #Object, + #name : 'InMemoryPetOrderRepository', + #superclass : 'Object', #instVars : [ 'orders', 'nextId', @@ -8,34 +8,36 @@ Class { 'orderStatus', 'updateTimestamps' ], - #category : #'Stargate-Examples-PetStore' + #category : 'Stargate-Examples-PetStore', + #package : 'Stargate-Examples', + #tag : 'PetStore' } -{ #category : #querying } +{ #category : 'querying' } InMemoryPetOrderRepository >> count [ ^ orders size ] -{ #category : #querying } +{ #category : 'querying' } InMemoryPetOrderRepository >> findAll [ ^ orders ] -{ #category : #querying } +{ #category : 'querying' } InMemoryPetOrderRepository >> findIdentifiedBy: anId [ ^ orderById at: anId ifAbsent: [ ObjectNotFound signal ] ] -{ #category : #querying } +{ #category : 'querying' } InMemoryPetOrderRepository >> identifierOf: aPetOrder [ ^ orderById keyAtValue: aPetOrder ] -{ #category : #initialization } +{ #category : 'initialization' } InMemoryPetOrderRepository >> initialize [ super initialize. @@ -46,13 +48,13 @@ InMemoryPetOrderRepository >> initialize [ nextId := 1 ] -{ #category : #private } +{ #category : 'private' } InMemoryPetOrderRepository >> lastModificationOf: aPetOrder [ ^ updateTimestamps at: (self identifierOf: aPetOrder) ] -{ #category : #private } +{ #category : 'private' } InMemoryPetOrderRepository >> recordIdAndUpdateTimestampFor: order [ orderById at: nextId put: order. @@ -62,13 +64,13 @@ InMemoryPetOrderRepository >> recordIdAndUpdateTimestampFor: order [ updateTimestamps at: nextId put: 1 ] -{ #category : #querying } +{ #category : 'querying' } InMemoryPetOrderRepository >> statusOf: anOrder [ ^ orderStatus at: ( self identifierOf: anOrder ) ifAbsent: [ ObjectNotFound signal ] ] -{ #category : #management } +{ #category : 'management' } InMemoryPetOrderRepository >> store: aPetOrder [ orders add: aPetOrder. @@ -77,7 +79,7 @@ InMemoryPetOrderRepository >> store: aPetOrder [ ^ aPetOrder ] -{ #category : #management } +{ #category : 'management' } InMemoryPetOrderRepository >> updateStatusOf: order to: aTargetStatus [ | id | diff --git a/source/Stargate-Examples/InMemoryPetRepository.class.st b/source/Stargate-Examples/InMemoryPetRepository.class.st index 3938dc1..45465dc 100644 --- a/source/Stargate-Examples/InMemoryPetRepository.class.st +++ b/source/Stargate-Examples/InMemoryPetRepository.class.st @@ -1,40 +1,42 @@ Class { - #name : #InMemoryPetRepository, - #superclass : #Object, + #name : 'InMemoryPetRepository', + #superclass : 'Object', #instVars : [ 'pets', 'petById', 'updateTimestamps', 'nextId' ], - #category : #'Stargate-Examples-PetStore' + #category : 'Stargate-Examples-PetStore', + #package : 'Stargate-Examples', + #tag : 'PetStore' } -{ #category : #querying } +{ #category : 'querying' } InMemoryPetRepository >> count [ ^ pets size ] -{ #category : #querying } +{ #category : 'querying' } InMemoryPetRepository >> findAll [ ^ pets ] -{ #category : #querying } +{ #category : 'querying' } InMemoryPetRepository >> findIdentifiedBy: anId [ ^ petById at: anId ifAbsent: [ ObjectNotFound signal ] ] -{ #category : #'private - repository' } +{ #category : 'private - repository' } InMemoryPetRepository >> identifierOf: aPet [ ^ petById keyAtValue: aPet ] -{ #category : #initialization } +{ #category : 'initialization' } InMemoryPetRepository >> initialize [ super initialize. @@ -44,19 +46,19 @@ InMemoryPetRepository >> initialize [ nextId := 1 ] -{ #category : #'private - repository' } +{ #category : 'private - repository' } InMemoryPetRepository >> lastModificationOf: aPet [ ^ updateTimestamps at: (self identifierOf: aPet) ] -{ #category : #management } +{ #category : 'management' } InMemoryPetRepository >> purge: aPet [ pets remove: aPet ] -{ #category : #'private - repository' } +{ #category : 'private - repository' } InMemoryPetRepository >> recordIdAndUpdateTimestampFor: newPet [ petById at: nextId put: newPet. @@ -65,7 +67,7 @@ InMemoryPetRepository >> recordIdAndUpdateTimestampFor: newPet [ updateTimestamps at: nextId put: 1 ] -{ #category : #management } +{ #category : 'management' } InMemoryPetRepository >> store: aPet [ pets add: aPet. @@ -74,7 +76,7 @@ InMemoryPetRepository >> store: aPet [ ^ aPet ] -{ #category : #management } +{ #category : 'management' } InMemoryPetRepository >> update: pet with: updatedPet [ pet synchronizeWith: updatedPet. diff --git a/source/Stargate-Examples/Pet.class.st b/source/Stargate-Examples/Pet.class.st index f73d7f9..4f9fdac 100644 --- a/source/Stargate-Examples/Pet.class.st +++ b/source/Stargate-Examples/Pet.class.st @@ -2,23 +2,25 @@ I'm a toy abstraction used just as an example " Class { - #name : #Pet, - #superclass : #Object, + #name : 'Pet', + #superclass : 'Object', #instVars : [ 'name', 'type', 'status' ], - #category : #'Stargate-Examples-PetStore' + #category : 'Stargate-Examples-PetStore', + #package : 'Stargate-Examples', + #tag : 'PetStore' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } Pet class >> named: aName ofType: aPetType [ ^ self named: aName ofType: aPetType withStatus: 'new' ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } Pet class >> named: aName ofType: aPetType withStatus: status [ AssertionChecker @@ -29,7 +31,7 @@ Pet class >> named: aName ofType: aPetType withStatus: status [ ^ self new initializeNamed: aName ofType: aPetType withStatus: status ] -{ #category : #initialization } +{ #category : 'initialization' } Pet >> initializeNamed: aName ofType: aPetType withStatus: aStatus [ name := aName. @@ -37,17 +39,17 @@ Pet >> initializeNamed: aName ofType: aPetType withStatus: aStatus [ status := aStatus ] -{ #category : #accessing } +{ #category : 'accessing' } Pet >> name [ ^ name ] -{ #category : #accessing } +{ #category : 'accessing' } Pet >> status [ ^ status ] -{ #category : #updating } +{ #category : 'updating' } Pet >> synchronizeWith: aPet [ name := aPet name. @@ -55,7 +57,7 @@ Pet >> synchronizeWith: aPet [ status := aPet status ] -{ #category : #accessing } +{ #category : 'accessing' } Pet >> type [ ^ type ] diff --git a/source/Stargate-Examples/PetOrder.class.st b/source/Stargate-Examples/PetOrder.class.st index 7256ad6..8d05a2a 100644 --- a/source/Stargate-Examples/PetOrder.class.st +++ b/source/Stargate-Examples/PetOrder.class.st @@ -2,35 +2,37 @@ I'm a toy abstraction used just as an example " Class { - #name : #PetOrder, - #superclass : #Object, + #name : 'PetOrder', + #superclass : 'Object', #instVars : [ 'pet', 'date' ], - #category : #'Stargate-Examples-PetStore' + #category : 'Stargate-Examples-PetStore', + #package : 'Stargate-Examples', + #tag : 'PetStore' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } PetOrder class >> for: aPetReference on: aDateAndTime [ ^self new initializeFor: aPetReference on: aDateAndTime ] -{ #category : #accessing } +{ #category : 'accessing' } PetOrder >> date [ ^ date ] -{ #category : #initialization } +{ #category : 'initialization' } PetOrder >> initializeFor: aPetReference on: aDateAndTime [ pet := aPetReference. date := aDateAndTime ] -{ #category : #accessing } +{ #category : 'accessing' } PetOrder >> pet [ ^ pet diff --git a/source/Stargate-Examples/PetOrdersRESTfulController.class.st b/source/Stargate-Examples/PetOrdersRESTfulController.class.st index 3a4457c..735bbc9 100644 --- a/source/Stargate-Examples/PetOrdersRESTfulController.class.st +++ b/source/Stargate-Examples/PetOrdersRESTfulController.class.st @@ -2,30 +2,32 @@ I'm an example RESTful Controller implementing Pet Order resource management " Class { - #name : #PetOrdersRESTfulController, - #superclass : #SingleResourceRESTfulController, + #name : 'PetOrdersRESTfulController', + #superclass : 'SingleResourceRESTfulController', #instVars : [ 'ordersRepository', 'commentsRequestHandler', 'commentsByOrderId', 'ordersRequestHandler' ], - #category : #'Stargate-Examples-PetStore' + #category : 'Stargate-Examples-PetStore', + #package : 'Stargate-Examples', + #tag : 'PetStore' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } PetOrdersRESTfulController class >> new [ ^ self persistingTo: InMemoryPetOrderRepository new ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } PetOrdersRESTfulController class >> persistingTo: aRepository [ ^ self basicNew initializePersistingTo: aRepository ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> affect: builder withMediaControlsFor: order locatedAt: location [ | status | @@ -43,7 +45,7 @@ PetOrdersRESTfulController >> affect: builder withMediaControlsFor: order locate builder addLink: location / 'comments' asUrl relatedTo: 'comments' ] -{ #category : #'API - orders' } +{ #category : 'API - orders' } PetOrdersRESTfulController >> cancelOrderBasedOn: httpRequest within: requestContext [ ^ ordersRequestHandler @@ -53,25 +55,25 @@ PetOrdersRESTfulController >> cancelOrderBasedOn: httpRequest within: requestCon thenDo: [ :order | ordersRepository updateStatusOf: order to: 'canceled' ] ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> cancelTemplate [ ^ '<1s>/cancel' expandMacrosWith: self identifierTemplate ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> commentIdentifierIn: httpRequest [ ^ httpRequest at: self commentIdentifierKey ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> commentIdentifierKey [ ^ #commentIdentifier asString ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> commentIdentifierTemplate [ ^ '<1s>/%<<2s>:<3s>>' @@ -80,19 +82,19 @@ PetOrdersRESTfulController >> commentIdentifierTemplate [ with: self typeIdConstraint asString ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> commentsForOrderIn: httpRequest [ ^ commentsByOrderId at: ( self identifierIn: httpRequest ) ifAbsent: [ #() ] ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> commentsTemplate [ ^ '<1s><2s>' expandMacrosWith: self identifierTemplate with: commentsRequestHandler endpoint ] -{ #category : #'API - orders' } +{ #category : 'API - orders' } PetOrdersRESTfulController >> completeOrderBasedOn: httpRequest within: requestContext [ ^ ordersRequestHandler @@ -102,13 +104,13 @@ PetOrdersRESTfulController >> completeOrderBasedOn: httpRequest within: requestC thenDo: [ :order | ordersRepository updateStatusOf: order to: 'completed' ] ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> completeTemplate [ ^ '<1s>/complete' expandMacrosWith: self identifierTemplate ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> configureOrderDecodingOn: reader [ ^ reader @@ -122,7 +124,7 @@ PetOrdersRESTfulController >> configureOrderDecodingOn: reader [ nextAs: PetOrder ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> configureOrderEncodingOn: writer within: requestContext [ writer @@ -137,7 +139,7 @@ PetOrdersRESTfulController >> configureOrderEncodingOn: writer within: requestCo ] ] -{ #category : #'API - comments' } +{ #category : 'API - comments' } PetOrdersRESTfulController >> createCommentBasedOn: httpRequest within: requestContext [ ^ commentsRequestHandler @@ -154,7 +156,7 @@ PetOrdersRESTfulController >> createCommentBasedOn: httpRequest within: requestC ] ] -{ #category : #'API - orders' } +{ #category : 'API - orders' } PetOrdersRESTfulController >> createOrderBasedOn: httpRequest within: requestContext [ ^ ordersRequestHandler @@ -167,7 +169,7 @@ PetOrdersRESTfulController >> createOrderBasedOn: httpRequest within: requestCon ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareCancelOrderRoute [ ^ RouteSpecification @@ -176,7 +178,7 @@ PetOrdersRESTfulController >> declareCancelOrderRoute [ evaluating: [ :httpRequest :requestContext | self cancelOrderBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareCompleteOrderRoute [ ^ RouteSpecification @@ -185,7 +187,7 @@ PetOrdersRESTfulController >> declareCompleteOrderRoute [ evaluating: [ :httpRequest :requestContext | self completeOrderBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareCreateOrderCommentRoute [ ^ RouteSpecification @@ -194,7 +196,7 @@ PetOrdersRESTfulController >> declareCreateOrderCommentRoute [ evaluating: [ :httpRequest :requestContext | self createCommentBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareCreateOrderRoute [ ^ RouteSpecification @@ -203,7 +205,7 @@ PetOrdersRESTfulController >> declareCreateOrderRoute [ evaluating: [ :httpRequest :requestContext | self createOrderBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareDeleteOrderCommentRoute [ ^ RouteSpecification @@ -213,7 +215,7 @@ PetOrdersRESTfulController >> declareDeleteOrderCommentRoute [ [ :httpRequest :requestContext | self deleteOrderCommentBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareGetOrderCommentRoute [ ^ RouteSpecification @@ -222,7 +224,7 @@ PetOrdersRESTfulController >> declareGetOrderCommentRoute [ evaluating: [ :httpRequest :requestContext | self orderCommentBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareGetOrderCommentsRoute [ ^ RouteSpecification @@ -231,7 +233,7 @@ PetOrdersRESTfulController >> declareGetOrderCommentsRoute [ evaluating: [ :httpRequest :requestContext | self orderCommentsBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareGetOrderRoute [ ^ RouteSpecification @@ -240,7 +242,7 @@ PetOrdersRESTfulController >> declareGetOrderRoute [ evaluating: [ :httpRequest :requestContext | self getOrderBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetOrdersRESTfulController >> declareUpdateOrderCommentRoute [ ^ RouteSpecification @@ -250,7 +252,7 @@ PetOrdersRESTfulController >> declareUpdateOrderCommentRoute [ [ :httpRequest :requestContext | self updateOrderCommentBasedOn: httpRequest within: requestContext ] ] -{ #category : #'API - comments' } +{ #category : 'API - comments' } PetOrdersRESTfulController >> deleteOrderCommentBasedOn: httpRequest within: requestContext [ ^ commentsRequestHandler @@ -260,7 +262,7 @@ PetOrdersRESTfulController >> deleteOrderCommentBasedOn: httpRequest within: req thenDo: [ :comment | ( self commentsForOrderIn: httpRequest ) remove: comment ] ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> encodeComments: resource [ ^ resource isArray @@ -271,7 +273,7 @@ PetOrdersRESTfulController >> encodeComments: resource [ ifFalse: [ resource asString ] ] -{ #category : #'API - orders' } +{ #category : 'API - orders' } PetOrdersRESTfulController >> getOrderBasedOn: httpRequest within: requestContext [ ^ ordersRequestHandler @@ -285,7 +287,7 @@ PetOrdersRESTfulController >> getOrderBasedOn: httpRequest within: requestContex ] ] -{ #category : #initialization } +{ #category : 'initialization' } PetOrdersRESTfulController >> initializeCommentsRequestHandler [ commentsRequestHandler := RESTfulRequestHandlerBuilder new @@ -310,7 +312,7 @@ PetOrdersRESTfulController >> initializeCommentsRequestHandler [ build ] -{ #category : #initialization } +{ #category : 'initialization' } PetOrdersRESTfulController >> initializeOrdersRequestHandler [ ordersRequestHandler := RESTfulRequestHandlerBuilder new @@ -333,7 +335,7 @@ PetOrdersRESTfulController >> initializeOrdersRequestHandler [ build ] -{ #category : #initialization } +{ #category : 'initialization' } PetOrdersRESTfulController >> initializePersistingTo: aPetRepository [ ordersRepository := aPetRepository. @@ -343,7 +345,7 @@ PetOrdersRESTfulController >> initializePersistingTo: aPetRepository [ initializeCommentsRequestHandler ] -{ #category : #'API - comments' } +{ #category : 'API - comments' } PetOrdersRESTfulController >> orderCommentBasedOn: httpRequest within: requestContext [ ^ commentsRequestHandler @@ -353,7 +355,7 @@ PetOrdersRESTfulController >> orderCommentBasedOn: httpRequest within: requestCo [ :commentIndex | ( self commentsForOrderIn: httpRequest ) at: commentIndex ifAbsent: [ ObjectNotFound signal ] ] ] -{ #category : #'API - comments' } +{ #category : 'API - comments' } PetOrdersRESTfulController >> orderCommentsBasedOn: httpRequest within: requestContext [ ^ commentsRequestHandler @@ -362,32 +364,32 @@ PetOrdersRESTfulController >> orderCommentsBasedOn: httpRequest within: requestC getCollection: [ ( self commentsForOrderIn: httpRequest ) asArray ] ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> orderVersion1dot0dot0MediaType [ ^ self jsonMediaType: 'order' vendoredBy: 'stargate' version: '1.0.0' ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> requestHandler [ ^ ordersRequestHandler ] -{ #category : #configuring } +{ #category : 'configuring' } PetOrdersRESTfulController >> serverUrl: aServerUrl [ super serverUrl: aServerUrl. commentsRequestHandler serverUrl: aServerUrl ] -{ #category : #private } +{ #category : 'private' } PetOrdersRESTfulController >> typeIdConstraint [ ^ IsInteger ] -{ #category : #'API - comments' } +{ #category : 'API - comments' } PetOrdersRESTfulController >> updateOrderCommentBasedOn: httpRequest within: requestContext [ ^ commentsRequestHandler diff --git a/source/Stargate-Examples/PetStoreApplication.class.st b/source/Stargate-Examples/PetStoreApplication.class.st index 49e2ae3..802f15c 100644 --- a/source/Stargate-Examples/PetStoreApplication.class.st +++ b/source/Stargate-Examples/PetStoreApplication.class.st @@ -1,47 +1,49 @@ Class { - #name : #PetStoreApplication, - #superclass : #StargateApplication, - #category : #'Stargate-Examples' + #name : 'PetStoreApplication', + #superclass : 'StargateApplication', + #category : 'Stargate-Examples-PetStore', + #package : 'Stargate-Examples', + #tag : 'PetStore' } -{ #category : #accessing } +{ #category : 'accessing' } PetStoreApplication class >> commandName [ ^ 'pet-store' ] -{ #category : #accessing } +{ #category : 'accessing' } PetStoreApplication class >> description [ ^'A RESTful API for Pet stores' ] -{ #category : #accessing } +{ #category : 'accessing' } PetStoreApplication class >> initialize [ self initializeVersion ] -{ #category : #private } +{ #category : 'private' } PetStoreApplication class >> projectName [ ^ 'Stargate' ] -{ #category : #private } +{ #category : 'private' } PetStoreApplication class >> sectionsForStargateConfiguration [ ^ #( 'Pet Store' ) , super sectionsForStargateConfiguration ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } PetStoreApplication >> controllersToInstall [ ^ Array with: PetsRESTfulController new with: PetOrdersRESTfulController new ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } PetStoreApplication >> stargateConfiguration [ ^self configuration petStore stargate diff --git a/source/Stargate-Examples/PetsRESTfulController.class.st b/source/Stargate-Examples/PetsRESTfulController.class.st index f51ebb0..68cf65f 100644 --- a/source/Stargate-Examples/PetsRESTfulController.class.st +++ b/source/Stargate-Examples/PetsRESTfulController.class.st @@ -2,28 +2,30 @@ I'm an example RESTful Controller implementing Pet resource management " Class { - #name : #PetsRESTfulController, - #superclass : #SingleResourceRESTfulController, + #name : 'PetsRESTfulController', + #superclass : 'SingleResourceRESTfulController', #instVars : [ 'petsRepository', 'requestHandler' ], - #category : #'Stargate-Examples-PetStore' + #category : 'Stargate-Examples-PetStore', + #package : 'Stargate-Examples', + #tag : 'PetStore' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } PetsRESTfulController class >> new [ ^ self persistingTo: InMemoryPetRepository new ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } PetsRESTfulController class >> persistingTo: aPetRepository [ ^ self basicNew initializePersistingTo: aPetRepository ] -{ #category : #private } +{ #category : 'private' } PetsRESTfulController >> addPaginationControlsTo: requestContext basedOn: url start: start limit: limit end: end count: total [ start = 1 @@ -48,7 +50,7 @@ PetsRESTfulController >> addPaginationControlsTo: requestContext basedOn: url st ] ] -{ #category : #private } +{ #category : 'private' } PetsRESTfulController >> configurePetEncodingOn: writer within: requestContext [ writer @@ -60,7 +62,7 @@ PetsRESTfulController >> configurePetEncodingOn: writer within: requestContext [ ] ] -{ #category : #private } +{ #category : 'private' } PetsRESTfulController >> configurePetSummaryEncodingOn: writer within: requestContext [ writer @@ -72,7 +74,7 @@ PetsRESTfulController >> configurePetSummaryEncodingOn: writer within: requestCo ] ] -{ #category : #API } +{ #category : 'API' } PetsRESTfulController >> createPetBasedOn: httpRequest within: requestContext [ ^ requestHandler @@ -83,7 +85,7 @@ PetsRESTfulController >> createPetBasedOn: httpRequest within: requestContext [ thenDo: [ :pet | petsRepository store: pet ] ] -{ #category : #routes } +{ #category : 'routes' } PetsRESTfulController >> declareCreatePetRoute [ ^ RouteSpecification @@ -92,7 +94,7 @@ PetsRESTfulController >> declareCreatePetRoute [ evaluating: [ :httpRequest :requestContext | self createPetBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetsRESTfulController >> declareDeletePetRoute [ ^ RouteSpecification @@ -101,7 +103,7 @@ PetsRESTfulController >> declareDeletePetRoute [ evaluating: [ :httpRequest :requestContext | self deletePetBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetsRESTfulController >> declareGetPetRoute [ ^ RouteSpecification @@ -110,7 +112,7 @@ PetsRESTfulController >> declareGetPetRoute [ evaluating: [ :httpRequest :requestContext | self getPetBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetsRESTfulController >> declareGetPetsRoute [ ^ RouteSpecification @@ -119,7 +121,7 @@ PetsRESTfulController >> declareGetPetsRoute [ evaluating: [ :httpRequest :requestContext | self getPetsBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } PetsRESTfulController >> declareUpdatePetRoute [ ^ RouteSpecification @@ -128,7 +130,7 @@ PetsRESTfulController >> declareUpdatePetRoute [ evaluating: [ :httpRequest :requestContext | self updatePetBasedOn: httpRequest within: requestContext ] ] -{ #category : #API } +{ #category : 'API' } PetsRESTfulController >> deletePetBasedOn: httpRequest within: requestContext [ ^ requestHandler @@ -138,7 +140,7 @@ PetsRESTfulController >> deletePetBasedOn: httpRequest within: requestContext [ thenDo: [ :pet | petsRepository purge: pet ] ] -{ #category : #API } +{ #category : 'API' } PetsRESTfulController >> getPetBasedOn: httpRequest within: requestContext [ ^ requestHandler @@ -147,7 +149,7 @@ PetsRESTfulController >> getPetBasedOn: httpRequest within: requestContext [ get: [ :id | petsRepository findIdentifiedBy: id ] ] -{ #category : #API } +{ #category : 'API' } PetsRESTfulController >> getPetsBasedOn: httpRequest within: requestContext [ ^ requestHandler @@ -174,14 +176,14 @@ PetsRESTfulController >> getPetsBasedOn: httpRequest within: requestContext [ ] ] -{ #category : #initialization } +{ #category : 'initialization' } PetsRESTfulController >> initializePersistingTo: aPetRepository [ petsRepository := aPetRepository. self initializeRequestHandler ] -{ #category : #initialization } +{ #category : 'initialization' } PetsRESTfulController >> initializeRequestHandler [ requestHandler := RESTfulRequestHandlerBuilder new @@ -219,31 +221,31 @@ PetsRESTfulController >> initializeRequestHandler [ build ] -{ #category : #'accessing - media types' } +{ #category : 'accessing - media types' } PetsRESTfulController >> petSummaryVersion1dot0dot0MediaType [ ^ self jsonMediaType: 'pet.summary' vendoredBy: 'stargate' version: '1.0.0' ] -{ #category : #'accessing - media types' } +{ #category : 'accessing - media types' } PetsRESTfulController >> petVersion1dot0dot0MediaType [ ^ self jsonMediaType: 'pet' vendoredBy: 'stargate' version: '1.0.0' ] -{ #category : #private } +{ #category : 'private' } PetsRESTfulController >> requestHandler [ ^ requestHandler ] -{ #category : #private } +{ #category : 'private' } PetsRESTfulController >> typeIdConstraint [ ^ IsInteger ] -{ #category : #API } +{ #category : 'API' } PetsRESTfulController >> updatePetBasedOn: httpRequest within: requestContext [ ^ requestHandler @@ -261,7 +263,7 @@ PetsRESTfulController >> updatePetBasedOn: httpRequest within: requestContext [ ] ] -{ #category : #private } +{ #category : 'private' } PetsRESTfulController >> urlFrom: url startingAt: start limitedTo: limit [ ^ url copy diff --git a/source/Stargate-Examples/SouthAmericanCurrenciesApplication.class.st b/source/Stargate-Examples/SouthAmericanCurrenciesApplication.class.st index ce37038..d7050a0 100644 --- a/source/Stargate-Examples/SouthAmericanCurrenciesApplication.class.st +++ b/source/Stargate-Examples/SouthAmericanCurrenciesApplication.class.st @@ -1,35 +1,37 @@ Class { - #name : #SouthAmericanCurrenciesApplication, - #superclass : #StargateApplication, - #category : #'Stargate-Examples' + #name : 'SouthAmericanCurrenciesApplication', + #superclass : 'StargateApplication', + #category : 'Stargate-Examples-Currencies', + #package : 'Stargate-Examples', + #tag : 'Currencies' } -{ #category : #accessing } +{ #category : 'accessing' } SouthAmericanCurrenciesApplication class >> commandName [ ^ 'currencies' ] -{ #category : #accessing } +{ #category : 'accessing' } SouthAmericanCurrenciesApplication class >> description [ ^'API for South american currencies' ] -{ #category : #initialization } +{ #category : 'initialization' } SouthAmericanCurrenciesApplication class >> initialize [ self initializeVersion ] -{ #category : #private } +{ #category : 'private' } SouthAmericanCurrenciesApplication class >> projectName [ ^ 'Stargate' ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } SouthAmericanCurrenciesApplication >> controllersToInstall [ ^ Array with: SouthAmericanCurrenciesRESTfulController new diff --git a/source/Stargate-Examples/SouthAmericanCurrenciesRESTfulController.class.st b/source/Stargate-Examples/SouthAmericanCurrenciesRESTfulController.class.st index 8a3f0b9..1fce0ac 100644 --- a/source/Stargate-Examples/SouthAmericanCurrenciesRESTfulController.class.st +++ b/source/Stargate-Examples/SouthAmericanCurrenciesRESTfulController.class.st @@ -5,24 +5,26 @@ I'm a example of a RESTful controller: - don't using hypermedia " Class { - #name : #SouthAmericanCurrenciesRESTfulController, - #superclass : #SingleResourceRESTfulController, + #name : 'SouthAmericanCurrenciesRESTfulController', + #superclass : 'SingleResourceRESTfulController', #instVars : [ 'banknotesByCurrency', 'banknotesRequestHandler', 'currenciesRequestHandler', 'currenciesByLanguage' ], - #category : #'Stargate-Examples-Currencies' + #category : 'Stargate-Examples-Currencies', + #package : 'Stargate-Examples', + #tag : 'Currencies' } -{ #category : #private } +{ #category : 'private' } SouthAmericanCurrenciesRESTfulController >> banknotesTemplate [ ^ '<1s><2s>' expandMacrosWith: self identifierTemplate with: banknotesRequestHandler endpoint ] -{ #category : #API } +{ #category : 'API' } SouthAmericanCurrenciesRESTfulController >> currenciesBasedOn: httpRequest within: requestContext [ ^ currenciesRequestHandler @@ -31,7 +33,7 @@ SouthAmericanCurrenciesRESTfulController >> currenciesBasedOn: httpRequest withi getCollection: [ self currenciesInLanguageAt: requestContext ] ] -{ #category : #private } +{ #category : 'private' } SouthAmericanCurrenciesRESTfulController >> currenciesInLanguageAt: requestContext [ | targetLanguage | @@ -42,7 +44,7 @@ SouthAmericanCurrenciesRESTfulController >> currenciesInLanguageAt: requestConte ^ currenciesByLanguage at: targetLanguage ] -{ #category : #API } +{ #category : 'API' } SouthAmericanCurrenciesRESTfulController >> currencyBanknotesBasedOn: httpRequest within: requestContext [ ^ banknotesRequestHandler @@ -51,7 +53,7 @@ SouthAmericanCurrenciesRESTfulController >> currencyBanknotesBasedOn: httpReques getCollection: [ banknotesByCurrency at: ( self identifierIn: httpRequest ) ] ] -{ #category : #API } +{ #category : 'API' } SouthAmericanCurrenciesRESTfulController >> currencyBasedOn: httpRequest within: requestContext [ ^ currenciesRequestHandler @@ -64,19 +66,19 @@ SouthAmericanCurrenciesRESTfulController >> currencyBasedOn: httpRequest within: ] ] -{ #category : #private } +{ #category : 'private' } SouthAmericanCurrenciesRESTfulController >> currencyNamed: aName symbol: aSymbol isoCode: anIsoCode [ ^ StargateCurrency named: aName symbol: aSymbol isoCode: anIsoCode ] -{ #category : #private } +{ #category : 'private' } SouthAmericanCurrenciesRESTfulController >> currencyVersion1dot0dot0MediaType [ ^ self jsonMediaType: 'currency' vendoredBy: 'stargate' version: '1.0.0' ] -{ #category : #routes } +{ #category : 'routes' } SouthAmericanCurrenciesRESTfulController >> declareGetCurrenciesRoute [ ^ RouteSpecification @@ -85,7 +87,7 @@ SouthAmericanCurrenciesRESTfulController >> declareGetCurrenciesRoute [ evaluating: [ :httpRequest :requestContext | self currenciesBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } SouthAmericanCurrenciesRESTfulController >> declareGetCurrencyBanknotesRoute [ ^ RouteSpecification @@ -94,7 +96,7 @@ SouthAmericanCurrenciesRESTfulController >> declareGetCurrencyBanknotesRoute [ evaluating: [ :httpRequest :requestContext | self currencyBanknotesBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } SouthAmericanCurrenciesRESTfulController >> declareGetCurrencyRoute [ ^ RouteSpecification @@ -103,7 +105,7 @@ SouthAmericanCurrenciesRESTfulController >> declareGetCurrencyRoute [ evaluating: [ :httpRequest :requestContext | self currencyBasedOn: httpRequest within: requestContext ] ] -{ #category : #initialization } +{ #category : 'initialization' } SouthAmericanCurrenciesRESTfulController >> initialize [ super initialize. @@ -114,7 +116,7 @@ SouthAmericanCurrenciesRESTfulController >> initialize [ initializeBanknotesRequestHandler ] -{ #category : #initialization } +{ #category : 'initialization' } SouthAmericanCurrenciesRESTfulController >> initializeBanknotesByCurrency [ banknotesByCurrency := Dictionary new @@ -132,7 +134,7 @@ SouthAmericanCurrenciesRESTfulController >> initializeBanknotesByCurrency [ yourself ] -{ #category : #initialization } +{ #category : 'initialization' } SouthAmericanCurrenciesRESTfulController >> initializeBanknotesRequestHandler [ banknotesRequestHandler := RESTfulRequestHandlerBuilder new @@ -146,7 +148,7 @@ SouthAmericanCurrenciesRESTfulController >> initializeBanknotesRequestHandler [ build ] -{ #category : #initialization } +{ #category : 'initialization' } SouthAmericanCurrenciesRESTfulController >> initializeCurrencies [ currenciesByLanguage := Dictionary new @@ -183,7 +185,7 @@ SouthAmericanCurrenciesRESTfulController >> initializeCurrencies [ yourself ] -{ #category : #initialization } +{ #category : 'initialization' } SouthAmericanCurrenciesRESTfulController >> initializeCurrenciesRequestHandler [ currenciesRequestHandler := RESTfulRequestHandlerBuilder new @@ -211,13 +213,13 @@ SouthAmericanCurrenciesRESTfulController >> initializeCurrenciesRequestHandler [ build ] -{ #category : #private } +{ #category : 'private' } SouthAmericanCurrenciesRESTfulController >> requestHandler [ ^ currenciesRequestHandler ] -{ #category : #private } +{ #category : 'private' } SouthAmericanCurrenciesRESTfulController >> typeIdConstraint [ ^ IsObject diff --git a/source/Stargate-Examples/StargateCurrency.class.st b/source/Stargate-Examples/StargateCurrency.class.st index 96349d5..68aebc9 100644 --- a/source/Stargate-Examples/StargateCurrency.class.st +++ b/source/Stargate-Examples/StargateCurrency.class.st @@ -2,23 +2,25 @@ I'm a simple model of a currency " Class { - #name : #StargateCurrency, - #superclass : #Object, + #name : 'StargateCurrency', + #superclass : 'Object', #instVars : [ 'name', 'symbol', 'isoCode' ], - #category : #'Stargate-Examples-Currencies' + #category : 'Stargate-Examples-Currencies', + #package : 'Stargate-Examples', + #tag : 'Currencies' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } StargateCurrency class >> named: aName symbol: aSymbol isoCode: anIsoCode [ ^ self new initializeNamed: aName symbol: aSymbol isoCode: anIsoCode ] -{ #category : #initialization } +{ #category : 'initialization' } StargateCurrency >> initializeNamed: aName symbol: aSymbol isoCode: anIsoCode [ name := aName. @@ -26,19 +28,19 @@ StargateCurrency >> initializeNamed: aName symbol: aSymbol isoCode: anIsoCode [ isoCode := anIsoCode ] -{ #category : #accessing } +{ #category : 'accessing' } StargateCurrency >> isoCode [ ^ isoCode ] -{ #category : #accessing } +{ #category : 'accessing' } StargateCurrency >> name [ ^ name ] -{ #category : #accessing } +{ #category : 'accessing' } StargateCurrency >> symbol [ ^ symbol diff --git a/source/Stargate-Examples/package.st b/source/Stargate-Examples/package.st index 78e86ed..add9b22 100644 --- a/source/Stargate-Examples/package.st +++ b/source/Stargate-Examples/package.st @@ -1 +1 @@ -Package { #name : #'Stargate-Examples' } +Package { #name : 'Stargate-Examples' } diff --git a/source/Stargate-Metrics-HTTP/HTTPMetrics.class.st b/source/Stargate-Metrics-HTTP/HTTPMetrics.class.st index 23d2472..0e7767f 100644 --- a/source/Stargate-Metrics-HTTP/HTTPMetrics.class.st +++ b/source/Stargate-Metrics-HTTP/HTTPMetrics.class.st @@ -2,44 +2,45 @@ I'm a provider of metrics related to HTTP requests " Class { - #name : #HTTPMetrics, - #superclass : #MetricProvider, + #name : 'HTTPMetrics', + #superclass : 'MetricProvider', #instVars : [ 'groupedRequestCount', 'groupedResponseSize', 'groupedRequestResponseDuration', 'categoriesFilter' ], - #category : #'Stargate-Metrics-HTTP' + #category : 'Stargate-Metrics-HTTP', + #package : 'Stargate-Metrics-HTTP' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } HTTPMetrics class >> configuredBy: pluginConfiguration [ ^ self basicNew initializeConfiguredBy: ( pluginConfiguration at: self providerName ifAbsent: [ Dictionary new ] ) ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } HTTPMetrics class >> new [ ^ self configuredBy: Dictionary new ] -{ #category : #accessing } +{ #category : 'accessing' } HTTPMetrics class >> providerName [ ^ 'http' ] -{ #category : #initialization } +{ #category : 'initialization' } HTTPMetrics >> finalize [ super finalize. self uninstall ] -{ #category : #calculating } +{ #category : 'calculating' } HTTPMetrics >> gatherMetrics [ ^ groupedRequestCount @@ -51,7 +52,7 @@ HTTPMetrics >> gatherMetrics [ ] ] -{ #category : #'event handling' } +{ #category : 'event handling' } HTTPMetrics >> handleEvent: aZnServerTransactionEvent [ | labels | @@ -65,7 +66,7 @@ HTTPMetrics >> handleEvent: aZnServerTransactionEvent [ increaseRequestResponseDurationAt: labels with: aZnServerTransactionEvent duration ] -{ #category : #'event handling' } +{ #category : 'event handling' } HTTPMetrics >> handleSimplifiedEvent: aZnSimplifiedServerTransactionEvent [ | labels | @@ -78,7 +79,7 @@ HTTPMetrics >> handleSimplifiedEvent: aZnSimplifiedServerTransactionEvent [ increaseRequestResponseDurationAt: labels with: aZnSimplifiedServerTransactionEvent duration ] -{ #category : #'private - accumulating' } +{ #category : 'private - accumulating' } HTTPMetrics >> increaseRequestCountAt: labels [ | previousCount | @@ -88,7 +89,7 @@ HTTPMetrics >> increaseRequestCountAt: labels [ groupedRequestCount at: labels put: previousCount + 1 ] -{ #category : #'private - accumulating' } +{ #category : 'private - accumulating' } HTTPMetrics >> increaseRequestResponseDurationAt: labels with: aMillisecondsCount [ | previousDuration | @@ -97,7 +98,7 @@ HTTPMetrics >> increaseRequestResponseDurationAt: labels with: aMillisecondsCoun groupedRequestResponseDuration at: labels put: previousDuration + aMillisecondsCount ] -{ #category : #'private - accumulating' } +{ #category : 'private - accumulating' } HTTPMetrics >> increaseResponseSizeAt: labels with: aByteCount [ | previousSize | @@ -106,7 +107,7 @@ HTTPMetrics >> increaseResponseSizeAt: labels with: aByteCount [ groupedResponseSize at: labels put: previousSize + aByteCount ] -{ #category : #initialization } +{ #category : 'initialization' } HTTPMetrics >> initializeConfiguredBy: providerConfiguration [ categoriesFilter := providerConfiguration at: #breakdownCategories @@ -116,17 +117,21 @@ HTTPMetrics >> initializeConfiguredBy: providerConfiguration [ self resetCounters ] -{ #category : #actions } +{ #category : 'actions' } HTTPMetrics >> installOn: teapotServer [ ZnLogEvent announcer - when: ZnSimplifiedServerTransactionEvent do: [ :event | self handleSimplifiedEvent: event ]; - when: ZnServerTransactionEvent do: [ :event | self handleEvent: event ]. + when: ZnSimplifiedServerTransactionEvent + do: [ :event | self handleSimplifiedEvent: event ] + for: self; + when: ZnServerTransactionEvent + do: [ :event | self handleEvent: event ] + for: self. teapotServer server setLogLevelAtLeastTo: 2 ] -{ #category : #'private - metrics' } +{ #category : 'private - metrics' } HTTPMetrics >> labelsFor: aServerTransactionEvent [ ^ categoriesFilter @@ -138,7 +143,7 @@ HTTPMetrics >> labelsFor: aServerTransactionEvent [ with: #url_template -> aServerTransactionEvent urlTemplate ) ] -{ #category : #'private - metrics' } +{ #category : 'private - metrics' } HTTPMetrics >> requestCountMetric [ | builder | @@ -153,7 +158,7 @@ HTTPMetrics >> requestCountMetric [ ^ builder build ] -{ #category : #'private - metrics' } +{ #category : 'private - metrics' } HTTPMetrics >> requestResponseDurationMetric [ | builder | @@ -168,7 +173,7 @@ HTTPMetrics >> requestResponseDurationMetric [ ^ builder build ] -{ #category : #initialization } +{ #category : 'initialization' } HTTPMetrics >> resetCounters [ groupedRequestCount := Dictionary new. @@ -176,7 +181,7 @@ HTTPMetrics >> resetCounters [ groupedRequestResponseDuration := Dictionary new ] -{ #category : #'private - metrics' } +{ #category : 'private - metrics' } HTTPMetrics >> responseSizeMetric [ | builder | @@ -191,7 +196,7 @@ HTTPMetrics >> responseSizeMetric [ ^ builder build ] -{ #category : #actions } +{ #category : 'actions' } HTTPMetrics >> uninstall [ ZnLogEvent announcer unsubscribe: self. diff --git a/source/Stargate-Metrics-HTTP/package.st b/source/Stargate-Metrics-HTTP/package.st index e3ea6d7..be0664e 100644 --- a/source/Stargate-Metrics-HTTP/package.st +++ b/source/Stargate-Metrics-HTTP/package.st @@ -1 +1 @@ -Package { #name : #'Stargate-Metrics-HTTP' } +Package { #name : 'Stargate-Metrics-HTTP' } diff --git a/source/Stargate-Model/AllowAnyOriginPolicy.class.st b/source/Stargate-Model/AllowAnyOriginPolicy.class.st index cad8915..5b8e5ed 100644 --- a/source/Stargate-Model/AllowAnyOriginPolicy.class.st +++ b/source/Stargate-Model/AllowAnyOriginPolicy.class.st @@ -2,12 +2,14 @@ I'm a policy configuring a CORS filter in such a way that sets Access-Control-Allow-Origin header to allow any origin. " Class { - #name : #AllowAnyOriginPolicy, - #superclass : #AllowOriginPolicy, - #category : #'Stargate-Model-CORS' + #name : 'AllowAnyOriginPolicy', + #superclass : 'AllowOriginPolicy', + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'configuring headers' } +{ #category : 'configuring headers' } AllowAnyOriginPolicy >> applyOn: aResponse for: aRequest using: aHandler [ aHandler setAnyOriginAllowedOn: aResponse diff --git a/source/Stargate-Model/AllowOriginPolicy.class.st b/source/Stargate-Model/AllowOriginPolicy.class.st index d766adf..d86957e 100644 --- a/source/Stargate-Model/AllowOriginPolicy.class.st +++ b/source/Stargate-Model/AllowOriginPolicy.class.st @@ -1,10 +1,12 @@ Class { - #name : #AllowOriginPolicy, - #superclass : #Object, - #category : #'Stargate-Model-CORS' + #name : 'AllowOriginPolicy', + #superclass : 'Object', + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'configuring headers' } +{ #category : 'configuring headers' } AllowOriginPolicy >> applyOn: aResponse for: aRequest using: aHandler [ self subclassResponsibility diff --git a/source/Stargate-Model/AllowSpecifiedOriginsPolicy.class.st b/source/Stargate-Model/AllowSpecifiedOriginsPolicy.class.st index a3654bf..004770d 100644 --- a/source/Stargate-Model/AllowSpecifiedOriginsPolicy.class.st +++ b/source/Stargate-Model/AllowSpecifiedOriginsPolicy.class.st @@ -2,21 +2,23 @@ I'm a policy configuring a CORS filter in such a way that sets Access-Control-Allow-Origin header to a specified set of origins. " Class { - #name : #AllowSpecifiedOriginsPolicy, - #superclass : #AllowOriginPolicy, + #name : 'AllowSpecifiedOriginsPolicy', + #superclass : 'AllowOriginPolicy', #instVars : [ 'allowedOrigins' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } AllowSpecifiedOriginsPolicy class >> onlyFrom: anUrlCollection [ ^ self new initializeOnlyFrom: ( anUrlCollection collect: #asWebOrigin ) ] -{ #category : #'configuring headers' } +{ #category : 'configuring headers' } AllowSpecifiedOriginsPolicy >> applyOn: aResponse for: aRequest using: aHandler [ | requestOrigin | @@ -25,15 +27,14 @@ AllowSpecifiedOriginsPolicy >> applyOn: aResponse for: aRequest using: aHandler allowedOrigins detect: [ :origin | origin = requestOrigin ] - ifFound: [ :allowedOrigin | + ifFound: [ :allowedOrigin | aHandler set: allowedOrigin asAllowOriginOn: aResponse. - allowedOrigins size > 1 - ifTrue: [ aResponse addToVary: aHandler headerNames >> #origin ] + allowedOrigins size > 1 ifTrue: [ aResponse addToVary: aHandler headerNames >> #origin ] ] ifNone: [ aRequest abort: TeaResponse noContent ] ] -{ #category : #initialization } +{ #category : 'initialization' } AllowSpecifiedOriginsPolicy >> initializeOnlyFrom: origins [ allowedOrigins := origins diff --git a/source/Stargate-Model/AuthenticationFilter.class.st b/source/Stargate-Model/AuthenticationFilter.class.st index c4eb321..bbf5bae 100644 --- a/source/Stargate-Model/AuthenticationFilter.class.st +++ b/source/Stargate-Model/AuthenticationFilter.class.st @@ -2,12 +2,14 @@ I'm an abstract class representing an authentication filter to be applied as a before filter and perform an auth validation. I will take into consideration the Authorization header on the request and return a 401 / Unauthorized in case the credentials are invalid. " Class { - #name : #AuthenticationFilter, - #superclass : #Object, - #category : #'Stargate-Model-Auth' + #name : 'AuthenticationFilter', + #superclass : 'Object', + #category : 'Stargate-Model-Auth', + #package : 'Stargate-Model', + #tag : 'Auth' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } AuthenticationFilter class >> basedOn: configuration [ ^ self allSubclasses @@ -16,37 +18,37 @@ AuthenticationFilter class >> basedOn: configuration [ ifNone: [ self signalMissingConfiguration ] ] -{ #category : #private } +{ #category : 'private' } AuthenticationFilter class >> canHandle: configuration [ ^ self subclassResponsibility ] -{ #category : #private } +{ #category : 'private' } AuthenticationFilter class >> configuredBy: configuration [ ^ self subclassResponsibility ] -{ #category : #private } +{ #category : 'private' } AuthenticationFilter class >> signalMissingConfiguration [ ^ ObjectNotFound signal: 'Missing authentication configuration' ] -{ #category : #accessing } +{ #category : 'accessing' } AuthenticationFilter >> authChallenge [ ^ self subclassResponsibility ] -{ #category : #private } +{ #category : 'private' } AuthenticationFilter >> checkCredentials: authorization for: httpRequest within: requestContext ifInvalid: aBlock [ self subclassResponsibility ] -{ #category : #evaluating } +{ #category : 'evaluating' } AuthenticationFilter >> evaluateActionOnRequest: httpRequest within: requestContext [ | authorization | @@ -61,7 +63,7 @@ AuthenticationFilter >> evaluateActionOnRequest: httpRequest within: requestCont ifInvalid: [ httpRequest abort: ( ZnResponse unauthorized: self authChallenge ) ] ] -{ #category : #evaluating } +{ #category : 'evaluating' } AuthenticationFilter >> teaEvalActionOnRequest: httpRequest [ self evaluateActionOnRequest: httpRequest within: HttpRequestContext new diff --git a/source/Stargate-Model/CachingDirectivesBuilder.class.st b/source/Stargate-Model/CachingDirectivesBuilder.class.st index 58ee627..dd6292e 100644 --- a/source/Stargate-Model/CachingDirectivesBuilder.class.st +++ b/source/Stargate-Model/CachingDirectivesBuilder.class.st @@ -2,16 +2,18 @@ I'm a builder of caching headers, translating a Smalltalk expression inside a block into a command that adds a cache-control header (and the expires header) to the response before being sent. " Class { - #name : #CachingDirectivesBuilder, - #superclass : #Object, + #name : 'CachingDirectivesBuilder', + #superclass : 'Object', #instVars : [ 'directives', 'currentCondition' ], - #category : #'Stargate-Model-Caching' + #category : 'Stargate-Model-Caching', + #package : 'Stargate-Model', + #tag : 'Caching' } -{ #category : #private } +{ #category : 'private' } CachingDirectivesBuilder >> addCacheControlNamed: aName [ | condition | @@ -22,25 +24,25 @@ CachingDirectivesBuilder >> addCacheControlNamed: aName [ [ :response :context :resource | ( condition cull: response cull: resource ) then: [ response addCachingDirective: aName ] ] ] -{ #category : #private } +{ #category : 'private' } CachingDirectivesBuilder >> addCacheControlNamed: aName withString: aString [ self addCacheControlNamed: ( '<1s>="<2s>"' expandMacrosWith: aName with: aString ) ] -{ #category : #private } +{ #category : 'private' } CachingDirectivesBuilder >> addCacheControlNamed: aName withToken: aValue [ self addCacheControlNamed: ( '<1s>=<2p>' expandMacrosWith: aName with: aValue ) ] -{ #category : #private } +{ #category : 'private' } CachingDirectivesBuilder >> alwaysApplyDirectives [ currentCondition := [ :response | true ] ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> beAvailableFor: aDuration [ ^ self @@ -49,19 +51,19 @@ CachingDirectivesBuilder >> beAvailableFor: aDuration [ expireIn: aDuration ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> beImmutable [ self addCacheControlNamed: 'immutable' ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> bePrivate [ self addCacheControlNamed: 'private' ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> bePrivateRestrictedTo: aFieldNameCollection [ | fieldsString | @@ -70,37 +72,37 @@ CachingDirectivesBuilder >> bePrivateRestrictedTo: aFieldNameCollection [ self addCacheControlNamed: 'private' withString: fieldsString ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> bePublic [ self addCacheControlNamed: 'public' ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> beStaleAfter: aDuration [ self addCacheControlNamed: 'Max-Age' withToken: aDuration asSeconds ] -{ #category : #building } +{ #category : 'building' } CachingDirectivesBuilder >> build [ ^ directives ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> configureUsing: aBlock [ aBlock cull: self ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> doNotCache [ self addCacheControlNamed: 'no-cache' ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> doNotCacheRestrictedTo: aFieldNameCollection [ | fieldsString | @@ -109,7 +111,7 @@ CachingDirectivesBuilder >> doNotCacheRestrictedTo: aFieldNameCollection [ self addCacheControlNamed: 'no-cache' withString: fieldsString ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> doNotExpire [ ^ self @@ -117,19 +119,19 @@ CachingDirectivesBuilder >> doNotExpire [ beAvailableFor: 365000000 seconds ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> doNotStore [ self addCacheControlNamed: 'no-store' ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> doNotTransform [ self addCacheControlNamed: 'no-transform' ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> expireIn: aDuration [ | condition | @@ -142,7 +144,7 @@ CachingDirectivesBuilder >> expireIn: aDuration [ ] ] -{ #category : #private } +{ #category : 'private' } CachingDirectivesBuilder >> fieldStringFor: aFieldNameCollection [ ^ String @@ -156,7 +158,7 @@ CachingDirectivesBuilder >> fieldStringFor: aFieldNameCollection [ ] ] -{ #category : #initialization } +{ #category : 'initialization' } CachingDirectivesBuilder >> initialize [ super initialize. @@ -164,13 +166,13 @@ CachingDirectivesBuilder >> initialize [ self alwaysApplyDirectives ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> mustRevalidate [ self addCacheControlNamed: 'must-revalidate' ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> requireRevalidation [ self @@ -178,7 +180,7 @@ CachingDirectivesBuilder >> requireRevalidation [ beStaleAfter: 0 seconds ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> when: aResponseCondition apply: aDirectiveConfiguration [ [ currentCondition := aResponseCondition. @@ -187,13 +189,13 @@ CachingDirectivesBuilder >> when: aResponseCondition apply: aDirectiveConfigurat ensure: [ self alwaysApplyDirectives ] ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> whenSharedBeStaleAfter: aDuration [ self addCacheControlNamed: 'S-MaxAge' withToken: aDuration asSeconds ] -{ #category : #configuring } +{ #category : 'configuring' } CachingDirectivesBuilder >> whenSharedMustRevalidate [ self addCacheControlNamed: 'proxy-revalidate' diff --git a/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandler.class.st b/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandler.class.st index cb0bfaa..bd66d88 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandler.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandler.class.st @@ -2,41 +2,43 @@ I'm a after filter handler for the actual request. I add CORS specific headers to the response. " Class { - #name : #CrossOriginResourceSharingActualRequestHandler, - #superclass : #CrossOriginResourceSharingHandler, + #name : 'CrossOriginResourceSharingActualRequestHandler', + #superclass : 'CrossOriginResourceSharingHandler', #instVars : [ 'allowOriginPolicy', 'optionalHeaderCommands' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } CrossOriginResourceSharingActualRequestHandler class >> allowing: anAllowOriginPolicy applying: addHeaderCommands [ ^ self new initializeAllowing: anAllowOriginPolicy applying: addHeaderCommands ] -{ #category : #initialization } +{ #category : 'initialization' } CrossOriginResourceSharingActualRequestHandler >> initializeAllowing: anAllowOriginPolicy applying: aCommandCollection [ allowOriginPolicy := anAllowOriginPolicy. optionalHeaderCommands := aCommandCollection. ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingActualRequestHandler >> setAllowedOriginOn: aResponse from: aRequest [ allowOriginPolicy applyOn: aResponse for: aRequest using: self ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingActualRequestHandler >> setOptionalHeadersOn: aResponse [ optionalHeaderCommands do: [ :command | command value: aResponse headers value: self headerNames ] ] -{ #category : #evaluating } +{ #category : 'evaluating' } CrossOriginResourceSharingActualRequestHandler >> teaEvalActionOnRequest: aRequest response: aResponse [ self setAllowedOriginOn: aResponse from: aRequest. diff --git a/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandlerBuilder.class.st b/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandlerBuilder.class.st index 3d3f1dc..1c64d87 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandlerBuilder.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingActualRequestHandlerBuilder.class.st @@ -2,42 +2,44 @@ I'm a builder for CrossOriginResourceSharingActualRequestHandler instances. " Class { - #name : #CrossOriginResourceSharingActualRequestHandlerBuilder, - #superclass : #CrossOriginResourceSharingRequestHandlerBuilder, + #name : 'CrossOriginResourceSharingActualRequestHandlerBuilder', + #superclass : 'CrossOriginResourceSharingRequestHandlerBuilder', #instVars : [ 'allowOriginPolicyBinding', 'addHeaderCommands' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingActualRequestHandlerBuilder >> allowAnyOrigin [ allowOriginPolicyBinding := Binding to: AllowAnyOriginPolicy new. ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingActualRequestHandlerBuilder >> allowCredentials [ addHeaderCommands add: [ :headers :headerNames | headers at: headerNames >> #accessControlAllowCredentials put: true asString ] ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingActualRequestHandlerBuilder >> allowOnlyFrom: origins [ allowOriginPolicyBinding := Binding to: ( AllowSpecifiedOriginsPolicy onlyFrom: origins ) ] -{ #category : #building } +{ #category : 'building' } CrossOriginResourceSharingActualRequestHandlerBuilder >> build [ ^ CrossOriginResourceSharingActualRequestHandler allowing: allowOriginPolicyBinding content applying: addHeaderCommands ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingActualRequestHandlerBuilder >> expose: exposedHeaders [ addHeaderCommands @@ -48,7 +50,7 @@ CrossOriginResourceSharingActualRequestHandlerBuilder >> expose: exposedHeaders ] ] -{ #category : #initialization } +{ #category : 'initialization' } CrossOriginResourceSharingActualRequestHandlerBuilder >> initialize [ super initialize. diff --git a/source/Stargate-Model/CrossOriginResourceSharingFilter.class.st b/source/Stargate-Model/CrossOriginResourceSharingFilter.class.st index 7e59c0c..dd9b008 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingFilter.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingFilter.class.st @@ -2,21 +2,23 @@ I'm a filter used to add CORS support to a HTTPBasedRESTfulAPI instance " Class { - #name : #CrossOriginResourceSharingFilter, - #superclass : #Object, + #name : 'CrossOriginResourceSharingFilter', + #superclass : 'Object', #instVars : [ 'filter' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'private - instance creation' } +{ #category : 'private - instance creation' } CrossOriginResourceSharingFilter class >> applying: aFilter [ ^ self new initializeApplying: aFilter ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } CrossOriginResourceSharingFilter class >> handleActualRequestByEvaluating: aHandler [ ^ self @@ -27,7 +29,7 @@ CrossOriginResourceSharingFilter class >> handleActualRequestByEvaluating: aHand ] ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } CrossOriginResourceSharingFilter class >> handlePreflightByEvaluating: aHandler [ ^ self applying: [ :teapotServer | @@ -37,19 +39,19 @@ CrossOriginResourceSharingFilter class >> handlePreflightByEvaluating: aHandler ] ] -{ #category : #testing } +{ #category : 'testing' } CrossOriginResourceSharingFilter class >> isForPreflight: request [ ^ ( request headers includesKey: 'Origin' ) and: [ request method = #OPTIONS ] ] -{ #category : #applying } +{ #category : 'applying' } CrossOriginResourceSharingFilter >> applyOn: aTeapot [ filter value: aTeapot ] -{ #category : #initialization } +{ #category : 'initialization' } CrossOriginResourceSharingFilter >> initializeApplying: aBlock [ filter := aBlock diff --git a/source/Stargate-Model/CrossOriginResourceSharingFilterBuilder.class.st b/source/Stargate-Model/CrossOriginResourceSharingFilterBuilder.class.st index 3430989..bf73bd6 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingFilterBuilder.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingFilterBuilder.class.st @@ -2,22 +2,31 @@ I'm a filter builder. I aim to provide a clean interface to configure CORS support during the configuration of a HTTPBasedRESTfulAPI instance. " Class { - #name : #CrossOriginResourceSharingFilterBuilder, - #superclass : #Object, + #name : 'CrossOriginResourceSharingFilterBuilder', + #superclass : 'Object', #instVars : [ 'actualRequestHandlerBuilder', - 'preflightHandlerBuilder' + 'preflightHandlerBuilder', + 'actualRequestHandlerBinding' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } CrossOriginResourceSharingFilterBuilder class >> using: aControllerCollection [ ^ self new initializeUsing: aControllerCollection ] -{ #category : #configuring } +{ #category : 'accessing' } +CrossOriginResourceSharingFilterBuilder >> actualRequestHandler [ + + ^ actualRequestHandlerBinding content +] + +{ #category : 'configuring' } CrossOriginResourceSharingFilterBuilder >> allowAnyOrigin [ preflightHandlerBuilder allowAnyOrigin. @@ -25,21 +34,21 @@ CrossOriginResourceSharingFilterBuilder >> allowAnyOrigin [ ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingFilterBuilder >> allowCredentials [ actualRequestHandlerBuilder allowCredentials. preflightHandlerBuilder allowCredentials ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingFilterBuilder >> allowOnlyFrom: origins [ preflightHandlerBuilder allowOnlyFrom: origins. actualRequestHandlerBuilder allowOnlyFrom: origins ] -{ #category : #initialization } +{ #category : 'initialization' } CrossOriginResourceSharingFilterBuilder >> allowedMethodsFrom: aControllerCollection [ | routes allowedMethods | @@ -61,42 +70,44 @@ CrossOriginResourceSharingFilterBuilder >> allowedMethodsFrom: aControllerCollec preflightHandlerBuilder allowMethods: allowedMethods ] -{ #category : #building } +{ #category : 'building' } CrossOriginResourceSharingFilterBuilder >> buildActualRequestFilter [ - ^ CrossOriginResourceSharingFilter handleActualRequestByEvaluating: actualRequestHandlerBuilder build + actualRequestHandlerBinding := Binding to: actualRequestHandlerBuilder build. + ^ CrossOriginResourceSharingFilter handleActualRequestByEvaluating: self actualRequestHandler ] -{ #category : #building } +{ #category : 'building' } CrossOriginResourceSharingFilterBuilder >> buildPreflightFilter [ ^ CrossOriginResourceSharingFilter handlePreflightByEvaluating: preflightHandlerBuilder build ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingFilterBuilder >> doNotCache [ preflightHandlerBuilder doNotCache ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingFilterBuilder >> expireIn: aDuration [ preflightHandlerBuilder expireIn: aDuration ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingFilterBuilder >> expose: headers [ preflightHandlerBuilder expose: headers. actualRequestHandlerBuilder expose: headers ] -{ #category : #initialization } +{ #category : 'initialization' } CrossOriginResourceSharingFilterBuilder >> initializeUsing: aControllerCollection [ preflightHandlerBuilder := CrossOriginResourceSharingPreflightHandlerBuilder new. actualRequestHandlerBuilder := CrossOriginResourceSharingActualRequestHandlerBuilder new. + actualRequestHandlerBinding := Binding undefinedExplainedBy: 'Actual request handler not built yet'. self allowedMethodsFrom: aControllerCollection ] diff --git a/source/Stargate-Model/CrossOriginResourceSharingHandler.class.st b/source/Stargate-Model/CrossOriginResourceSharingHandler.class.st index 34e1888..9f526a7 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingHandler.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingHandler.class.st @@ -1,13 +1,15 @@ Class { - #name : #CrossOriginResourceSharingHandler, - #superclass : #Object, + #name : 'CrossOriginResourceSharingHandler', + #superclass : 'Object', #classVars : [ 'Headers' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'class initialization' } +{ #category : 'class initialization' } CrossOriginResourceSharingHandler class >> initialize [ @@ -28,19 +30,19 @@ CrossOriginResourceSharingHandler class >> initialize [ to: 'Access-Control-Expose-Headers' ] -{ #category : #accessing } +{ #category : 'accessing' } CrossOriginResourceSharingHandler >> headerNames [ ^ Headers ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingHandler >> set: anOrigin asAllowOriginOn: aResponse [ aResponse headers at: self headerNames >> #accessControlAllowOrigin put: anOrigin asString ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingHandler >> setAnyOriginAllowedOn: aResponse [ aResponse headers at: self headerNames >> #accessControlAllowOrigin put: '*' diff --git a/source/Stargate-Model/CrossOriginResourceSharingPreflightHandler.class.st b/source/Stargate-Model/CrossOriginResourceSharingPreflightHandler.class.st index 777ab78..95e05cd 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingPreflightHandler.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingPreflightHandler.class.st @@ -2,23 +2,25 @@ I'm a before filter handler for the preflight request. " Class { - #name : #CrossOriginResourceSharingPreflightHandler, - #superclass : #CrossOriginResourceSharingHandler, + #name : 'CrossOriginResourceSharingPreflightHandler', + #superclass : 'CrossOriginResourceSharingHandler', #instVars : [ 'allowOriginPolicy', 'allowedMethodsByRoute', 'optionalHeaderCommands' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } CrossOriginResourceSharingPreflightHandler class >> allowing: anAllowOriginPolicy accessTo: allowMethods applying: headersCommands [ ^ self new initializeAllowing: anAllowOriginPolicy accessTo: allowMethods applying: headersCommands ] -{ #category : #initialization } +{ #category : 'initialization' } CrossOriginResourceSharingPreflightHandler >> initializeAllowing: anAllowOriginPolicy accessTo: methods applying: aCommandCollection [ allowOriginPolicy := anAllowOriginPolicy. @@ -26,7 +28,7 @@ CrossOriginResourceSharingPreflightHandler >> initializeAllowing: anAllowOriginP optionalHeaderCommands := aCommandCollection. ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingPreflightHandler >> setAllowedHeadersOn: aResponse from: aRequest [ aRequest headers @@ -41,7 +43,7 @@ CrossOriginResourceSharingPreflightHandler >> setAllowedHeadersOn: aResponse fro ] ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingPreflightHandler >> setAllowedMethodsOn: aResponse from: allowedMethods [ allowedMethods @@ -49,19 +51,19 @@ CrossOriginResourceSharingPreflightHandler >> setAllowedMethodsOn: aResponse fro [ :method | aResponse headers at: self headerNames >> #accessControlAllowMethods addSeparatedWithComma: method ] ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingPreflightHandler >> setAllowedOriginOn: aResponse from: aRequest [ allowOriginPolicy applyOn: aResponse for: aRequest using: self ] -{ #category : #'private - evaluating' } +{ #category : 'private - evaluating' } CrossOriginResourceSharingPreflightHandler >> setOptionalHeadersOn: aResponse [ optionalHeaderCommands do: [ :command | command value: aResponse headers value: self headerNames ] ] -{ #category : #evaluating } +{ #category : 'evaluating' } CrossOriginResourceSharingPreflightHandler >> teaEvalActionOnRequest: aRequest [ | response | @@ -78,7 +80,7 @@ CrossOriginResourceSharingPreflightHandler >> teaEvalActionOnRequest: aRequest [ ] ] -{ #category : #evaluating } +{ #category : 'evaluating' } CrossOriginResourceSharingPreflightHandler >> withAllowedMethodsFor: aUrl do: aBlock [ allowedMethodsByRoute keys diff --git a/source/Stargate-Model/CrossOriginResourceSharingPreflightHandlerBuilder.class.st b/source/Stargate-Model/CrossOriginResourceSharingPreflightHandlerBuilder.class.st index 5b9d760..9d09d20 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingPreflightHandlerBuilder.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingPreflightHandlerBuilder.class.st @@ -2,43 +2,45 @@ I'm a builder for CrossOriginResourceSharingPreflightHandlerBuilder instances. " Class { - #name : #CrossOriginResourceSharingPreflightHandlerBuilder, - #superclass : #CrossOriginResourceSharingRequestHandlerBuilder, + #name : 'CrossOriginResourceSharingPreflightHandlerBuilder', + #superclass : 'CrossOriginResourceSharingRequestHandlerBuilder', #instVars : [ 'allowedMethodsBinding', 'allowOriginPolicyBinding', 'addHeaderCommands' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingPreflightHandlerBuilder >> allowAnyOrigin [ allowOriginPolicyBinding := Binding to: AllowAnyOriginPolicy new. ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingPreflightHandlerBuilder >> allowCredentials [ addHeaderCommands add: [ :headers :headerNames | headers at: headerNames >> #accessControlAllowCredentials put: true asString ] ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingPreflightHandlerBuilder >> allowMethods: methods [ allowedMethodsBinding := Binding to: methods ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingPreflightHandlerBuilder >> allowOnlyFrom: origins [ allowOriginPolicyBinding := Binding to: ( AllowSpecifiedOriginsPolicy onlyFrom: origins ) ] -{ #category : #building } +{ #category : 'building' } CrossOriginResourceSharingPreflightHandlerBuilder >> build [ ^ CrossOriginResourceSharingPreflightHandler @@ -47,14 +49,14 @@ CrossOriginResourceSharingPreflightHandlerBuilder >> build [ applying: addHeaderCommands ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingPreflightHandlerBuilder >> doNotCache [ addHeaderCommands add: [ :headers :headerNames | headers at: headerNames >> #accessControlMaxAge put: -1 asString ] ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingPreflightHandlerBuilder >> expireIn: aDuration [ addHeaderCommands @@ -62,7 +64,7 @@ CrossOriginResourceSharingPreflightHandlerBuilder >> expireIn: aDuration [ [ :headers :headerNames | headers at: headerNames >> #accessControlMaxAge put: aDuration asSeconds asString ] ] -{ #category : #configuring } +{ #category : 'configuring' } CrossOriginResourceSharingPreflightHandlerBuilder >> expose: exposedHeaders [ addHeaderCommands @@ -73,7 +75,7 @@ CrossOriginResourceSharingPreflightHandlerBuilder >> expose: exposedHeaders [ ] ] -{ #category : #initialization } +{ #category : 'initialization' } CrossOriginResourceSharingPreflightHandlerBuilder >> initialize [ super initialize. diff --git a/source/Stargate-Model/CrossOriginResourceSharingRequestHandlerBuilder.class.st b/source/Stargate-Model/CrossOriginResourceSharingRequestHandlerBuilder.class.st index b38658f..6299c1e 100644 --- a/source/Stargate-Model/CrossOriginResourceSharingRequestHandlerBuilder.class.st +++ b/source/Stargate-Model/CrossOriginResourceSharingRequestHandlerBuilder.class.st @@ -1,10 +1,12 @@ Class { - #name : #CrossOriginResourceSharingRequestHandlerBuilder, - #superclass : #Object, - #category : #'Stargate-Model-CORS' + #name : 'CrossOriginResourceSharingRequestHandlerBuilder', + #superclass : 'Object', + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #building } +{ #category : 'building' } CrossOriginResourceSharingRequestHandlerBuilder >> build [ ^ self subclassResponsibility diff --git a/source/Stargate-Model/EntityTagHasher.class.st b/source/Stargate-Model/EntityTagHasher.class.st index a6ffb86..84ae04e 100644 --- a/source/Stargate-Model/EntityTagHasher.class.st +++ b/source/Stargate-Model/EntityTagHasher.class.st @@ -2,15 +2,17 @@ I'm responsible for generating a valid ETag hashing the objects included " Class { - #name : #EntityTagHasher, - #superclass : #Object, + #name : 'EntityTagHasher', + #superclass : 'Object', #instVars : [ 'toHash' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #calculating } +{ #category : 'calculating' } EntityTagHasher >> calculateHash [ | message | @@ -22,13 +24,13 @@ EntityTagHasher >> calculateHash [ ^ MessageDigestAlgorithm sha1 digestStringAsHexString: message ] -{ #category : #configuring } +{ #category : 'configuring' } EntityTagHasher >> include: anObjectToHash [ toHash add: anObjectToHash ] -{ #category : #initialization } +{ #category : 'initialization' } EntityTagHasher >> initialize [ super initialize. diff --git a/source/Stargate-Model/HTTPBasedRESTfulAPI.class.st b/source/Stargate-Model/HTTPBasedRESTfulAPI.class.st index e0b58c9..951c657 100644 --- a/source/Stargate-Model/HTTPBasedRESTfulAPI.class.st +++ b/source/Stargate-Model/HTTPBasedRESTfulAPI.class.st @@ -2,44 +2,57 @@ I represent an HTTP based RESTful API, serving one or more services. " Class { - #name : #HTTPBasedRESTfulAPI, - #superclass : #Object, + #name : 'HTTPBasedRESTfulAPI', + #superclass : 'Object', #instVars : [ 'teapotServer', 'controllers', 'errorHandlers', 'enabledOperationalPlugins', 'operationsConfiguration', - 'disabledOperationalPlugins' + 'disabledOperationalPlugins', + 'optionalCORSHandler' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } HTTPBasedRESTfulAPI class >> configuredBy: configuration installing: aRESTfulControllerCollection [ AssertionChecker enforce: [ aRESTfulControllerCollection notEmpty ] because: 'An API needs at least to expose one resource'. ^ self new initializeConfiguredBy: configuration installing: aRESTfulControllerCollection ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> addController: aRESTfulController [ controllers add: aRESTfulController ] -{ #category : #configuring } +{ #category : 'configuring' } HTTPBasedRESTfulAPI >> allowCrossOriginSharingApplying: aConfigurationBlock [ | builder | - builder := aConfigurationBlock - value: ( CrossOriginResourceSharingFilterBuilder using: controllers ). + builder := aConfigurationBlock value: + ( CrossOriginResourceSharingFilterBuilder using: controllers ). builder buildPreflightFilter applyOn: teapotServer. - builder buildActualRequestFilter applyOn: teapotServer + builder buildActualRequestFilter applyOn: teapotServer. + optionalCORSHandler := Optional containing: builder actualRequestHandler ] -{ #category : #configuring } +{ #category : 'private - configuring' } +HTTPBasedRESTfulAPI >> applyCrossSharingResourceConfigurationTo: response accordingTo: request [ + + optionalCORSHandler withContentDo: [ :handler | + ( request headers includesKey: 'Origin' ) then: [ + handler teaEvalActionOnRequest: request response: response ] + ] +] + +{ #category : 'configuring' } HTTPBasedRESTfulAPI >> authenticatedBy: anAuthorizationFilter [ teapotServer @@ -47,13 +60,13 @@ HTTPBasedRESTfulAPI >> authenticatedBy: anAuthorizationFilter [ when: [ :request | ( CrossOriginResourceSharingFilter isForPreflight: request ) not ] ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> configureErrorHandlers [ errorHandlers do: [ :errorHandler | teapotServer exception: errorHandler ] ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> configureRoutes [ | configurator | @@ -62,7 +75,7 @@ HTTPBasedRESTfulAPI >> configureRoutes [ controllers do: [ :controller | configurator addRoutesOf: controller ] ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> configureRoutesDeclaredByPlugin: anOperationalPluginType [ | configurator | @@ -72,7 +85,7 @@ HTTPBasedRESTfulAPI >> configureRoutesDeclaredByPlugin: anOperationalPluginType do: [ :controller | configurator addRoutesOf: controller ] ] -{ #category : #configuring } +{ #category : 'configuring' } HTTPBasedRESTfulAPI >> disable: anOperationalPluginType [ enabledOperationalPlugins @@ -91,7 +104,7 @@ HTTPBasedRESTfulAPI >> disable: anOperationalPluginType [ ] ] -{ #category : #configuring } +{ #category : 'configuring' } HTTPBasedRESTfulAPI >> enable: anOperationalPluginType [ disabledOperationalPlugins @@ -110,7 +123,7 @@ HTTPBasedRESTfulAPI >> enable: anOperationalPluginType [ ] ] -{ #category : #configuring } +{ #category : 'configuring' } HTTPBasedRESTfulAPI >> enable: anOperationalPluginEndpoint configuredBy: configuration [ | pluginToEnable | @@ -121,9 +134,10 @@ HTTPBasedRESTfulAPI >> enable: anOperationalPluginEndpoint configuredBy: configu pluginToEnable includeControllersIn: self ] -{ #category : #initialization } +{ #category : 'initialization' } HTTPBasedRESTfulAPI >> initializeConfiguredBy: configuration installing: aRESTfulControllerCollection [ + optionalCORSHandler := Optional unusedBecause: 'CORS not configured'. teapotServer := Teapot configure: configuration , {( #notFoundHandlerClass -> Tea405AwareNotFoundHandler )}. operationsConfiguration := configuration asDictionary at: #operations. @@ -133,14 +147,14 @@ HTTPBasedRESTfulAPI >> initializeConfiguredBy: configuration installing: aRESTfu initializeEnabledOperationalPlugins ] -{ #category : #initialization } +{ #category : 'initialization' } HTTPBasedRESTfulAPI >> initializeControllersWithAll: aRESTfulControllerCollection [ controllers := OrderedCollection with: ( OperationalPluginsRESTfulController on: self ). controllers addAll: aRESTfulControllerCollection ] -{ #category : #initialization } +{ #category : 'initialization' } HTTPBasedRESTfulAPI >> initializeEnabledOperationalPlugins [ enabledOperationalPlugins := OrderedSet new. @@ -155,27 +169,22 @@ HTTPBasedRESTfulAPI >> initializeEnabledOperationalPlugins [ thenDo: [ :plugin | self enable: plugin endpoint configuredBy: operationsConfiguration ] ] -{ #category : #initialization } +{ #category : 'initialization' } HTTPBasedRESTfulAPI >> initializeErrorHandlers [ errorHandlers := OrderedCollection new. - self - on: HTTPClientError - addErrorHandler: [ :clientError :request | - | json | - - json := NeoJSONWriter toStringPretty: clientError. - ( ZnResponse statusCode: clientError code ) - headers: - ( ZnHeaders defaultResponseHeaders - at: 'Access-Control-Allow-Origin' put: '*'; - yourself ); - entity: ( ZnEntity json: json ); - yourself - ] + self on: HTTPClientError addErrorHandler: [ :clientError :request | + | json response | + + json := NeoJSONWriter toStringPretty: clientError. + response := ZnResponse statusCode: clientError code. + response entity: ( ZnEntity json: json ). + self applyCrossSharingResourceConfigurationTo: response accordingTo: request. + response + ] ] -{ #category : #actions } +{ #category : 'actions' } HTTPBasedRESTfulAPI >> install [ self @@ -183,13 +192,13 @@ HTTPBasedRESTfulAPI >> install [ configureErrorHandlers ] -{ #category : #testing } +{ #category : 'testing' } HTTPBasedRESTfulAPI >> isEnabled: aPluginType [ ^ enabledOperationalPlugins anySatisfy: [ :plugin | plugin isA: aPluginType ] ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> markAsDisabled: plugin [ plugin stop. @@ -197,7 +206,7 @@ HTTPBasedRESTfulAPI >> markAsDisabled: plugin [ disabledOperationalPlugins add: plugin ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> markAsEnabled: plugin [ disabledOperationalPlugins remove: plugin ifAbsent: [ ]. @@ -205,19 +214,19 @@ HTTPBasedRESTfulAPI >> markAsEnabled: plugin [ plugin startOn: teapotServer ] -{ #category : #configuring } +{ #category : 'configuring' } HTTPBasedRESTfulAPI >> on: exception addErrorHandler: aDyadicBlock [ errorHandlers add: exception -> aDyadicBlock ] -{ #category : #accessing } +{ #category : 'accessing' } HTTPBasedRESTfulAPI >> operationsConfiguration [ ^ operationsConfiguration ] -{ #category : #configuring } +{ #category : 'configuring' } HTTPBasedRESTfulAPI >> removeRoutesDeclaredByPlugin: anOperationalPluginType [ ^ self withControllersDefinedByPlugin: anOperationalPluginType do: [ :controller | @@ -226,27 +235,27 @@ HTTPBasedRESTfulAPI >> removeRoutesDeclaredByPlugin: anOperationalPluginType [ ] ] -{ #category : #actions } +{ #category : 'actions' } HTTPBasedRESTfulAPI >> start [ enabledOperationalPlugins do: [ :plugin | plugin startOn: teapotServer ]. teapotServer start ] -{ #category : #actions } +{ #category : 'actions' } HTTPBasedRESTfulAPI >> stop [ teapotServer stop. enabledOperationalPlugins do: #stop ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> withConfigurationOf: plugin do: aPresentBlock ifAbsent: anAbsentBlock [ ^ operationsConfiguration at: plugin endpoint ifPresent: aPresentBlock ifAbsent: anAbsentBlock ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } HTTPBasedRESTfulAPI >> withControllersDefinedByPlugin: anOperationalPluginType do: aBlock [ controllers diff --git a/source/Stargate-Model/HttpRequestContext.class.st b/source/Stargate-Model/HttpRequestContext.class.st index cf630ee..aee979b 100644 --- a/source/Stargate-Model/HttpRequestContext.class.st +++ b/source/Stargate-Model/HttpRequestContext.class.st @@ -3,15 +3,17 @@ I'm a context that gets created each time an Http Request is proceesed. I can ca I also provide some facilities to manage Hypermedia Controls. " Class { - #name : #HttpRequestContext, - #superclass : #Object, + #name : 'HttpRequestContext', + #superclass : 'Object', #instVars : [ 'knownObjects' ], - #category : #'Stargate-Model-Routing' + #category : 'Stargate-Model-Routing', + #package : 'Stargate-Model', + #tag : 'Routing' } -{ #category : #pagination } +{ #category : 'pagination' } HttpRequestContext >> addPaginationLink: aUrl relatedTo: aRelationType [ | controls | @@ -26,14 +28,14 @@ HttpRequestContext >> addPaginationLink: aUrl relatedTo: aRelationType [ build ) ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> hold: anObject under: aConcept [ knownObjects at: aConcept put: anObject. ^ anObject ] -{ #category : #hypermedia } +{ #category : 'hypermedia' } HttpRequestContext >> holdAsHypermediaControls: aControlCollection for: resource [ | resourcesHypermediaControls | @@ -44,7 +46,7 @@ HttpRequestContext >> holdAsHypermediaControls: aControlCollection for: resource resourcesHypermediaControls at: resource put: aControlCollection ] -{ #category : #hypermedia } +{ #category : 'hypermedia' } HttpRequestContext >> hypermediaControlsFor: resource [ | hypermediaControls | @@ -53,20 +55,20 @@ HttpRequestContext >> hypermediaControlsFor: resource [ ^ hypermediaControls at: resource ifAbsent: [ #() ] ] -{ #category : #authorization } +{ #category : 'authorization' } HttpRequestContext >> includesPermission: aPermission [ ^ ( self objectUnder: #permissions ifNone: [ #() ] ) includes: aPermission ] -{ #category : #initialization } +{ #category : 'initialization' } HttpRequestContext >> initialize [ super initialize. knownObjects := IdentityDictionary new ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> objectUnder: aConcept [ ^ self @@ -74,61 +76,61 @@ HttpRequestContext >> objectUnder: aConcept [ ifNone: [ NotFound signal: ( 'Missing <1s> in the request context' expandMacrosWith: aConcept asString ) ] ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> objectUnder: aConcept ifNone: aBlock [ ^ knownObjects at: aConcept ifAbsent: aBlock ] -{ #category : #pagination } +{ #category : 'pagination' } HttpRequestContext >> paginationControls [ ^ (self objectUnder: #paginationLinks ifNone: [ #() ]) asArray ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> parentResource [ ^ self objectUnder: #parentResource ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> parentResource: anIdentifier [ self hold: anIdentifier under: #parentResource ] -{ #category : #authorization } +{ #category : 'authorization' } HttpRequestContext >> permissions: aPermissionCollection [ self hold: aPermissionCollection under: #permissions ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> targetLanguageTag [ ^ self objectUnder: #targetLanguageTag ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> targetLanguageTag: aLanguageTag [ ^ self hold: aLanguageTag under: #targetLanguageTag ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> targetMediaType [ ^ self objectUnder: #targetMediaType ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> targetMediaType: aMediaType [ ^ self hold: aMediaType under: #targetMediaType ] -{ #category : #accessing } +{ #category : 'accessing' } HttpRequestContext >> withTargetLanguageTagDo: aBlock [ knownObjects at: #targetLanguageTag ifPresent: aBlock diff --git a/source/Stargate-Model/HypermediaDrivenRESTfulRequestHandler.class.st b/source/Stargate-Model/HypermediaDrivenRESTfulRequestHandler.class.st index 9360f21..2545b9d 100644 --- a/source/Stargate-Model/HypermediaDrivenRESTfulRequestHandler.class.st +++ b/source/Stargate-Model/HypermediaDrivenRESTfulRequestHandler.class.st @@ -2,15 +2,17 @@ I represent a RESTful handler supporting hypermedia driven controllers. " Class { - #name : #HypermediaDrivenRESTfulRequestHandler, - #superclass : #RESTfulRequestHandlerBehavior, + #name : 'HypermediaDrivenRESTfulRequestHandler', + #superclass : 'RESTfulRequestHandlerBehavior', #instVars : [ 'mediaControlsFactory' ], - #category : #'Stargate-Model-HATEOAS' + #category : 'Stargate-Model-HATEOAS', + #package : 'Stargate-Model', + #tag : 'HATEOAS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } HypermediaDrivenRESTfulRequestHandler class >> resourceLocator: aResouceLocator paginationPolicy: aPaginationPolicy decodingRules: theDecodingRules encodingRules: theEncodingRules calculateEntityTagsWith: entityTagCalculator cachingDirectives: theCachingDirectives allowedLanguageTags: allowedLanguageTags drivenBy: aMediaControlsFactory handleErrorsWith: anExceptionHandler [ ^ self new @@ -25,14 +27,14 @@ HypermediaDrivenRESTfulRequestHandler class >> resourceLocator: aResouceLocator handleErrorsWith: anExceptionHandler ] -{ #category : #private } +{ #category : 'private' } HypermediaDrivenRESTfulRequestHandler >> encodeResource: resource as: mediaType within: requestContext [ self holdResource: resource controlsWithin: requestContext. ^ super encodeResource: resource as: mediaType within: requestContext ] -{ #category : #private } +{ #category : 'private' } HypermediaDrivenRESTfulRequestHandler >> encodeResourceCollection: resourceCollection basedOn: httpRequest within: requestContext [ requestContext @@ -48,7 +50,7 @@ HypermediaDrivenRESTfulRequestHandler >> encodeResourceCollection: resourceColle within: requestContext ] -{ #category : #private } +{ #category : 'private' } HypermediaDrivenRESTfulRequestHandler >> holdResource: resource controlsWithin: requestContext [ requestContext @@ -56,7 +58,7 @@ HypermediaDrivenRESTfulRequestHandler >> holdResource: resource controlsWithin: for: resource ] -{ #category : #initialization } +{ #category : 'initialization' } HypermediaDrivenRESTfulRequestHandler >> initializeResourceLocator: aResouceLocator paginationPolicy: aPaginationPolicy decodingRules: theDecodingRules @@ -81,7 +83,7 @@ HypermediaDrivenRESTfulRequestHandler >> initializeResourceLocator: aResouceLoca mediaControlsFactory := aMediaControlsFactory ] -{ #category : #private } +{ #category : 'private' } HypermediaDrivenRESTfulRequestHandler >> mediaControlsFor: resource within: requestContext [ ^ mediaControlsFactory diff --git a/source/Stargate-Model/JWTBearerAuthenticationFilter.class.st b/source/Stargate-Model/JWTBearerAuthenticationFilter.class.st index b19b0af..0a26890 100644 --- a/source/Stargate-Model/JWTBearerAuthenticationFilter.class.st +++ b/source/Stargate-Model/JWTBearerAuthenticationFilter.class.st @@ -2,16 +2,18 @@ I'm an authentication filter using Bearer tokens in JWT format " Class { - #name : #JWTBearerAuthenticationFilter, - #superclass : #AuthenticationFilter, + #name : 'JWTBearerAuthenticationFilter', + #superclass : 'AuthenticationFilter', #instVars : [ 'key', 'algorithm' ], - #category : #'Stargate-Model-Auth' + #category : 'Stargate-Model-Auth', + #package : 'Stargate-Model', + #tag : 'Auth' } -{ #category : #private } +{ #category : 'private' } JWTBearerAuthenticationFilter class >> canHandle: configuration [ | schema algorithm | @@ -22,7 +24,7 @@ JWTBearerAuthenticationFilter class >> canHandle: configuration [ JsonWebAlgorithm supportsAlgorithmNamed: algorithm ] ] ] -{ #category : #private } +{ #category : 'private' } JWTBearerAuthenticationFilter class >> configuredBy: configuration [ ^ self @@ -30,19 +32,19 @@ JWTBearerAuthenticationFilter class >> configuredBy: configuration [ forAlgorithmNamed: ( configuration at: #authAlgorithm ) ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } JWTBearerAuthenticationFilter class >> with: aKey forAlgorithmNamed: anAlgorithmName [ ^ self new initializeWith: aKey forAlgorithm: ( JsonWebAlgorithm named: anAlgorithmName ) ] -{ #category : #accessing } +{ #category : 'accessing' } JWTBearerAuthenticationFilter >> authChallenge [ ^ 'Bearer' ] -{ #category : #private } +{ #category : 'private' } JWTBearerAuthenticationFilter >> checkCredentials: authorization for: httpRequest within: requestContext ifInvalid: aBlock [ | tokenString | @@ -61,7 +63,7 @@ JWTBearerAuthenticationFilter >> checkCredentials: authorization for: httpReques do: [ :error | error return: aBlock value ] ] -{ #category : #initialization } +{ #category : 'initialization' } JWTBearerAuthenticationFilter >> initializeWith: aKey forAlgorithm: anAlgorithm [ key := aKey . diff --git a/source/Stargate-Model/MediaControlsBuilder.class.st b/source/Stargate-Model/MediaControlsBuilder.class.st index 84a2821..c290778 100644 --- a/source/Stargate-Model/MediaControlsBuilder.class.st +++ b/source/Stargate-Model/MediaControlsBuilder.class.st @@ -2,46 +2,48 @@ I'm a builder easing the creation of media controls " Class { - #name : #MediaControlsBuilder, - #superclass : #Object, + #name : 'MediaControlsBuilder', + #superclass : 'Object', #instVars : [ 'mediaControls', 'resourceLocatorBinding' ], - #category : #'Stargate-Model-HATEOAS' + #category : 'Stargate-Model-HATEOAS', + #package : 'Stargate-Model', + #tag : 'HATEOAS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } MediaControlsBuilder class >> locatingResourcesWith: aResourceLocator [ ^ self new initializeLocatingResourcesWith: aResourceLocator ] -{ #category : #adding } +{ #category : 'adding' } MediaControlsBuilder >> addAsSelfLink: aUrl [ ^ self addLink: aUrl relatedTo: 'self' ] -{ #category : #adding } +{ #category : 'adding' } MediaControlsBuilder >> addLink: aUrl relatedTo: aRelationType [ mediaControls add: aRelationType -> aUrl ] -{ #category : #adding } +{ #category : 'adding' } MediaControlsBuilder >> addRelativeLink: aRelativeUrl relatedTo: aRelationType [ mediaControls add: aRelationType -> ( resourceLocatorBinding content baseUrl / aRelativeUrl ) ] -{ #category : #building } +{ #category : 'building' } MediaControlsBuilder >> build [ ^ mediaControls asArray ] -{ #category : #initialization } +{ #category : 'initialization' } MediaControlsBuilder >> initialize [ super initialize. @@ -49,7 +51,7 @@ MediaControlsBuilder >> initialize [ resourceLocatorBinding := Binding undefinedExplainedBy: 'Missing resource locator' ] -{ #category : #initialization } +{ #category : 'initialization' } MediaControlsBuilder >> initializeLocatingResourcesWith: aResourceLocator [ resourceLocatorBinding := Binding to: aResourceLocator diff --git a/source/Stargate-Model/OperationalPlugin.class.st b/source/Stargate-Model/OperationalPlugin.class.st index dfdf145..aa40753 100644 --- a/source/Stargate-Model/OperationalPlugin.class.st +++ b/source/Stargate-Model/OperationalPlugin.class.st @@ -13,42 +13,44 @@ An operational plugin must have the following characteristics: " Class { - #name : #OperationalPlugin, - #superclass : #Object, - #category : #'Stargate-Model-Operations' + #name : 'OperationalPlugin', + #superclass : 'Object', + #category : 'Stargate-Model-Operations', + #package : 'Stargate-Model', + #tag : 'Operations' } -{ #category : #accessing } +{ #category : 'accessing' } OperationalPlugin class >> availablePlugins [ ^ self allLeafSubclasses ] -{ #category : #configuring } +{ #category : 'configuring' } OperationalPlugin class >> configureMediaControlsIn: builder within: requestContext [ self subclassResponsibility ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } OperationalPlugin class >> configuredBy: configuration [ ^ self subclassResponsibility ] -{ #category : #testing } +{ #category : 'testing' } OperationalPlugin class >> enabledByDefault [ ^ false ] -{ #category : #accessing } +{ #category : 'accessing' } OperationalPlugin class >> endpoint [ ^ self subclassResponsibility ] -{ #category : #accessing } +{ #category : 'accessing' } OperationalPlugin class >> pluginAt: endpoint [ ^ self availablePlugins @@ -56,7 +58,7 @@ OperationalPlugin class >> pluginAt: endpoint [ ifNone: [ ObjectNotFound signal: ( 'Plugin <1s> not available' expandMacrosWith: endpoint ) ] ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } OperationalPlugin class >> pluginConfigurationOn: configuration [ | selfConfiguration | @@ -70,37 +72,37 @@ OperationalPlugin class >> pluginConfigurationOn: configuration [ ^ selfConfiguration ] -{ #category : #accessing } +{ #category : 'accessing' } OperationalPlugin class >> pluginName [ ^ self subclassResponsibility ] -{ #category : #accessing } +{ #category : 'accessing' } OperationalPlugin >> endpoint [ ^ self class endpoint ] -{ #category : #configuring } +{ #category : 'configuring' } OperationalPlugin >> includeControllersIn: api [ self subclassResponsibility ] -{ #category : #accessing } +{ #category : 'accessing' } OperationalPlugin >> name [ ^ self class pluginName ] -{ #category : #printing } +{ #category : 'printing' } OperationalPlugin >> printOn: stream [ stream nextPutAll: self name ] -{ #category : #controlling } +{ #category : 'controlling' } OperationalPlugin >> startOn: teapotServer [ "This method is called when the server is started, giving @@ -109,7 +111,7 @@ OperationalPlugin >> startOn: teapotServer [ ] -{ #category : #controlling } +{ #category : 'controlling' } OperationalPlugin >> stop [ "This method is called when the server is stopped, giving diff --git a/source/Stargate-Model/OperationalPluginsRESTfulController.class.st b/source/Stargate-Model/OperationalPluginsRESTfulController.class.st index 32246ef..3e372cd 100644 --- a/source/Stargate-Model/OperationalPluginsRESTfulController.class.st +++ b/source/Stargate-Model/OperationalPluginsRESTfulController.class.st @@ -2,23 +2,25 @@ I'm a RESTful controller providing access to the list of available operational plugins and its endpoints " Class { - #name : #OperationalPluginsRESTfulController, - #superclass : #OperationsRESTfulController, + #name : 'OperationalPluginsRESTfulController', + #superclass : 'OperationsRESTfulController', #instVars : [ 'requestHandler', 'api' ], - #category : #'Stargate-Model-Operations' + #category : 'Stargate-Model-Operations', + #package : 'Stargate-Model', + #tag : 'Operations' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } OperationalPluginsRESTfulController class >> on: anHTTPBasedRESTfulAPI [ ^ ( self authenticationFilterBasedOn: anHTTPBasedRESTfulAPI operationsConfiguration ) initializeOn: anHTTPBasedRESTfulAPI ] -{ #category : #API } +{ #category : 'API' } OperationalPluginsRESTfulController >> changeOperationalPluginStatusBasedOn: httpRequest within: requestContext [ self assert: httpRequest isAuthorizedTo: self updatePermission within: requestContext. @@ -38,7 +40,7 @@ OperationalPluginsRESTfulController >> changeOperationalPluginStatusBasedOn: htt ] ] -{ #category : #private } +{ #category : 'private' } OperationalPluginsRESTfulController >> configureOperationalPluginEncodingOn: writer within: requestContext [ OperationalPlugin availablePlugins @@ -54,7 +56,7 @@ OperationalPluginsRESTfulController >> configureOperationalPluginEncodingOn: wri ] ] -{ #category : #routes } +{ #category : 'routes' } OperationalPluginsRESTfulController >> declareGetOperationalPluginRoute [ ^ RouteSpecification @@ -63,7 +65,7 @@ OperationalPluginsRESTfulController >> declareGetOperationalPluginRoute [ evaluating: [ :httpRequest :requestContext | self operationalPluginBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } OperationalPluginsRESTfulController >> declareGetOperationalPluginsRoute [ ^ RouteSpecification @@ -73,7 +75,7 @@ OperationalPluginsRESTfulController >> declareGetOperationalPluginsRoute [ [ :httpRequest :requestContext | self operationalPluginsBasedOn: httpRequest within: requestContext ] ] -{ #category : #routes } +{ #category : 'routes' } OperationalPluginsRESTfulController >> declareUpdateOperationalPluginRoute [ ^ RouteSpecification handling: #PATCH @@ -82,14 +84,14 @@ OperationalPluginsRESTfulController >> declareUpdateOperationalPluginRoute [ self changeOperationalPluginStatusBasedOn: httpRequest within: requestContext ] ] -{ #category : #initialization } +{ #category : 'initialization' } OperationalPluginsRESTfulController >> initializeOn: anHTTPBasedRESTfulAPI [ api := anHTTPBasedRESTfulAPI. self initializeRequestHandler ] -{ #category : #initialization } +{ #category : 'initialization' } OperationalPluginsRESTfulController >> initializeRequestHandler [ requestHandler := RESTfulRequestHandlerBuilder new @@ -112,7 +114,7 @@ OperationalPluginsRESTfulController >> initializeRequestHandler [ build ] -{ #category : #API } +{ #category : 'API' } OperationalPluginsRESTfulController >> operationalPluginBasedOn: httpRequest within: requestContext [ self assert: httpRequest isAuthorizedWithin: requestContext. @@ -123,13 +125,13 @@ OperationalPluginsRESTfulController >> operationalPluginBasedOn: httpRequest wit get: [ :endpoint | OperationalPlugin pluginAt: endpoint ] ] -{ #category : #private } +{ #category : 'private' } OperationalPluginsRESTfulController >> operationalPluginVersion1dot0dot0MediaType [ ^ self jsonMediaType: 'operational-plugin' vendoredBy: 'stargate' version: '1.0.0' ] -{ #category : #API } +{ #category : 'API' } OperationalPluginsRESTfulController >> operationalPluginsBasedOn: httpRequest within: requestContext [ self assert: httpRequest isAuthorizedWithin: requestContext. @@ -140,25 +142,25 @@ OperationalPluginsRESTfulController >> operationalPluginsBasedOn: httpRequest wi getCollection: [ OperationalPlugin availablePlugins ] ] -{ #category : #private } +{ #category : 'private' } OperationalPluginsRESTfulController >> requestHandler [ ^ requestHandler ] -{ #category : #private } +{ #category : 'private' } OperationalPluginsRESTfulController >> requiredPermission [ ^ 'read:operations' ] -{ #category : #querying } +{ #category : 'querying' } OperationalPluginsRESTfulController >> statusOf: aPluginType [ ^ ( api isEnabled: aPluginType ) then: [ 'ENABLED' ] otherwise: [ 'DISABLED' ] ] -{ #category : #private } +{ #category : 'private' } OperationalPluginsRESTfulController >> updatePermission [ ^ 'update:operations' diff --git a/source/Stargate-Model/OperationsRESTfulController.class.st b/source/Stargate-Model/OperationsRESTfulController.class.st index 72b7246..a98b838 100644 --- a/source/Stargate-Model/OperationsRESTfulController.class.st +++ b/source/Stargate-Model/OperationsRESTfulController.class.st @@ -2,60 +2,62 @@ I'm an abstract class providing behavior for all the RESTful controllers related to operations and operation plugins. " Class { - #name : #OperationsRESTfulController, - #superclass : #SingleResourceRESTfulController, + #name : 'OperationsRESTfulController', + #superclass : 'SingleResourceRESTfulController', #instVars : [ 'authenticationFilter' ], - #category : #'Stargate-Model-Operations' + #category : 'Stargate-Model-Operations', + #package : 'Stargate-Model', + #tag : 'Operations' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } OperationsRESTfulController class >> authenticationFilterBasedOn: configuration [ ^ self new initializeAuthenticationFilterBasedOn: configuration ] -{ #category : #testing } +{ #category : 'testing' } OperationsRESTfulController class >> isAbstract [ ^ self = OperationsRESTfulController ] -{ #category : #private } +{ #category : 'private' } OperationsRESTfulController >> assert: httpRequest isAuthorizedTo: permission within: requestContext [ ( requestContext includesPermission: permission ) ifFalse: [ httpRequest abort: ZnResponse forbidden ] ] -{ #category : #private } +{ #category : 'private' } OperationsRESTfulController >> assert: httpRequest isAuthorizedWithin: requestContext [ self assert: httpRequest isAuthorizedTo: self requiredPermission within: requestContext ] -{ #category : #initialization } +{ #category : 'initialization' } OperationsRESTfulController >> initializeAuthenticationFilterBasedOn: configuration [ authenticationFilter := AuthenticationFilter basedOn: configuration ] -{ #category : #private } +{ #category : 'private' } OperationsRESTfulController >> requiredPermission [ ^ self subclassResponsibility ] -{ #category : #accessing } +{ #category : 'accessing' } OperationsRESTfulController >> routes [ ^ super routes collect: [ :routeSpecification | routeSpecification authenticatedBy: authenticationFilter ] ] -{ #category : #private } +{ #category : 'private' } OperationsRESTfulController >> typeIdConstraint [ ^ IsObject diff --git a/source/Stargate-Model/PaginationSpecification.class.st b/source/Stargate-Model/PaginationSpecification.class.st index a5a2e88..e8ea1f9 100644 --- a/source/Stargate-Model/PaginationSpecification.class.st +++ b/source/Stargate-Model/PaginationSpecification.class.st @@ -2,16 +2,18 @@ I'm a pagination specification, used to know the start index and the expected page size " Class { - #name : #PaginationSpecification, - #superclass : #Object, + #name : 'PaginationSpecification', + #superclass : 'Object', #instVars : [ 'start', 'limit' ], - #category : #'Stargate-Model-Pagination' + #category : 'Stargate-Model-Pagination', + #package : 'Stargate-Model', + #tag : 'Pagination' } -{ #category : #'Instance creation' } +{ #category : 'Instance creation' } PaginationSpecification class >> startingAt: aNumber limitedTo: aLimit [ AssertionChecker @@ -21,26 +23,26 @@ PaginationSpecification class >> startingAt: aNumber limitedTo: aLimit [ ^ self new initializeStartingAt: ( aNumber max: 1 ) limitedTo: aLimit ] -{ #category : #accessing } +{ #category : 'accessing' } PaginationSpecification >> end [ ^ start + limit - 1 ] -{ #category : #'initialize - release' } +{ #category : 'initialize - release' } PaginationSpecification >> initializeStartingAt: anStartIndex limitedTo: aLimitCount [ start := anStartIndex. limit := aLimitCount ] -{ #category : #accessing } +{ #category : 'accessing' } PaginationSpecification >> limit [ ^ limit ] -{ #category : #printing } +{ #category : 'printing' } PaginationSpecification >> printOn: aStream [ aStream @@ -51,7 +53,7 @@ PaginationSpecification >> printOn: aStream [ print: limit ] -{ #category : #accessing } +{ #category : 'accessing' } PaginationSpecification >> start [ ^ start diff --git a/source/Stargate-Model/QualifiedLanguageRange.class.st b/source/Stargate-Model/QualifiedLanguageRange.class.st index c270670..a2b7b10 100644 --- a/source/Stargate-Model/QualifiedLanguageRange.class.st +++ b/source/Stargate-Model/QualifiedLanguageRange.class.st @@ -2,16 +2,18 @@ I'm a language range including a quality parameter as used in Accept-Language headers " Class { - #name : #QualifiedLanguageRange, - #superclass : #Object, + #name : 'QualifiedLanguageRange', + #superclass : 'Object', #instVars : [ 'languangeRange', 'quality' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } QualifiedLanguageRange class >> fromString: aString [ ^ ( aString substrings: ';' ) @@ -33,26 +35,26 @@ QualifiedLanguageRange class >> fromString: aString [ ] ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } QualifiedLanguageRange class >> qualifying: aLanguageRange with: aQualityFactor [ ^ self new initializeQualifying: aLanguageRange with: aQualityFactor ] -{ #category : #initialization } +{ #category : 'initialization' } QualifiedLanguageRange >> initializeQualifying: aLanguageRange with: aQualityFactor [ languangeRange := aLanguageRange. quality := aQualityFactor ] -{ #category : #accessing } +{ #category : 'accessing' } QualifiedLanguageRange >> quality [ ^ quality ] -{ #category : #accessing } +{ #category : 'accessing' } QualifiedLanguageRange >> range [ ^ languangeRange diff --git a/source/Stargate-Model/RESTfulControllerAcceptNegotiator.class.st b/source/Stargate-Model/RESTfulControllerAcceptNegotiator.class.st index 159733d..0fb3eab 100644 --- a/source/Stargate-Model/RESTfulControllerAcceptNegotiator.class.st +++ b/source/Stargate-Model/RESTfulControllerAcceptNegotiator.class.st @@ -2,28 +2,30 @@ I will provide the best representation (media type) to use for processing an HTTP Request given an available media type list " Class { - #name : #RESTfulControllerAcceptNegotiator, - #superclass : #Object, + #name : 'RESTfulControllerAcceptNegotiator', + #superclass : 'Object', #instVars : [ 'availableMediaTypes', 'availableLanguageTags' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RESTfulControllerAcceptNegotiator class >> accepting: aMediaTypeCollection [ ^ self accepting: aMediaTypeCollection inAnyOf: #() ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } RESTfulControllerAcceptNegotiator class >> accepting: aMediaTypeCollection inAnyOf: aLanguageTagCollection [ ^ self new initializeAccepting: aMediaTypeCollection inAnyOf: aLanguageTagCollection ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> acceptableMediaTypesIn: anHttpRequest [ | acceptHeaderContent | @@ -38,7 +40,7 @@ RESTfulControllerAcceptNegotiator >> acceptableMediaTypesIn: anHttpRequest [ otherwise: [ self splitMediaTypesIn: acceptHeaderContent ] ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> acceptableQualifiedLanguageRangesIn: anHttpRequest [ | acceptHeaderContent | @@ -55,7 +57,7 @@ RESTfulControllerAcceptNegotiator >> acceptableQualifiedLanguageRangesIn: anHttp otherwise: [ self splitQualifiedLanguageRangesIn: acceptHeaderContent ] ] -{ #category : #querying } +{ #category : 'querying' } RESTfulControllerAcceptNegotiator >> bestLanguageFor: anHttpRequest [ "This method returns the best suited language tag for the given request" @@ -73,7 +75,7 @@ RESTfulControllerAcceptNegotiator >> bestLanguageFor: anHttpRequest [ inAnyOf: availableLanguageTags ] -{ #category : #querying } +{ #category : 'querying' } RESTfulControllerAcceptNegotiator >> bestRepresentationFor: anHttpRequest [ "This method returns the best suited representation for the given request" @@ -82,14 +84,14 @@ RESTfulControllerAcceptNegotiator >> bestRepresentationFor: anHttpRequest [ HTTPNotAcceptable signal: 'Cannot generate a response entity with acceptable characteristics.' accepting: availableMediaTypes ] -{ #category : #'initialize - release' } +{ #category : 'initialize - release' } RESTfulControllerAcceptNegotiator >> initializeAccepting: aMediaTypeCollection inAnyOf: aLanguageTagCollection [ availableMediaTypes := aMediaTypeCollection. availableLanguageTags := aLanguageTagCollection ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> mediaTypesAvailableFor: aMediaType [ ^ availableMediaTypes @@ -98,7 +100,7 @@ RESTfulControllerAcceptNegotiator >> mediaTypesAvailableFor: aMediaType [ and: [ self versionIn: aMediaType canBeHandledBy: available ] ] ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> precedenceFor: aMediaType [ | precedence version versionParts | @@ -119,19 +121,19 @@ RESTfulControllerAcceptNegotiator >> precedenceFor: aMediaType [ ^ precedence ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> sortByPrecedence: mediaTypes [ ^ mediaTypes sorted: [ :mediaType | self precedenceFor: mediaType ] descending ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> splitMediaTypesIn: acceptList [ ^ ( ',' split: acceptList ) collect: [ :type | type asMediaType ] ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> splitQualifiedLanguageRangesIn: acceptLanguageList [ ^ ( ',' split: acceptLanguageList ) @@ -146,7 +148,7 @@ RESTfulControllerAcceptNegotiator >> splitQualifiedLanguageRangesIn: acceptLangu ] ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> versionIn: acceptable canBeHandledBy: available [ | acceptVersion availableVersion acceptVersionParts availableVersionParts | @@ -164,7 +166,7 @@ RESTfulControllerAcceptNegotiator >> versionIn: acceptable canBeHandledBy: avail ^ true ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> withAcceptableLanguageRangesIn: anHttpRequest do: aBlock [ | acceptable grouped | @@ -178,7 +180,7 @@ RESTfulControllerAcceptNegotiator >> withAcceptableLanguageRangesIn: anHttpReque do: [ :quality | ( grouped at: quality ) do: [ :qualifiedRange | aBlock value: qualifiedRange range ] ] ] -{ #category : #'private - accessing' } +{ #category : 'private - accessing' } RESTfulControllerAcceptNegotiator >> withAcceptableMediaTypesIn: anHttpRequest do: aBlock [ | acceptable grouped | diff --git a/source/Stargate-Model/RESTfulControllerDoNotPaginateCollectionsPolicy.class.st b/source/Stargate-Model/RESTfulControllerDoNotPaginateCollectionsPolicy.class.st index 2258fa9..ff8cbbb 100644 --- a/source/Stargate-Model/RESTfulControllerDoNotPaginateCollectionsPolicy.class.st +++ b/source/Stargate-Model/RESTfulControllerDoNotPaginateCollectionsPolicy.class.st @@ -2,37 +2,39 @@ I'm the policy indicating a RESTful controller to not support pagination of collections related to the controlled resource. " Class { - #name : #RESTfulControllerDoNotPaginateCollectionsPolicy, - #superclass : #RESTfulControllerPaginationPolicy, + #name : 'RESTfulControllerDoNotPaginateCollectionsPolicy', + #superclass : 'RESTfulControllerPaginationPolicy', #instVars : [ 'requestHandler' ], - #category : #'Stargate-Model-Pagination' + #category : 'Stargate-Model-Pagination', + #package : 'Stargate-Model', + #tag : 'Pagination' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RESTfulControllerDoNotPaginateCollectionsPolicy class >> for: aRequestHandler [ ^ self new initializeFor: aRequestHandler ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerDoNotPaginateCollectionsPolicy >> addPaginationControlsTo: mediaControls within: requestContext [ ^ mediaControls ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerDoNotPaginateCollectionsPolicy >> affect: response within: requestContext [ ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerDoNotPaginateCollectionsPolicy >> evaluateQuery: aQueryEvaluationBlock basedOn: httpRequest [ ^ requestHandler evaluateCollectionQuery: aQueryEvaluationBlock ] -{ #category : #initialization } +{ #category : 'initialization' } RESTfulControllerDoNotPaginateCollectionsPolicy >> initializeFor: aRequestHandler [ requestHandler := aRequestHandler diff --git a/source/Stargate-Model/RESTfulControllerDoNotRespondCreatedEntityPolicy.class.st b/source/Stargate-Model/RESTfulControllerDoNotRespondCreatedEntityPolicy.class.st index 9ff839c..87f3bcc 100644 --- a/source/Stargate-Model/RESTfulControllerDoNotRespondCreatedEntityPolicy.class.st +++ b/source/Stargate-Model/RESTfulControllerDoNotRespondCreatedEntityPolicy.class.st @@ -2,27 +2,29 @@ I'm a policy configuring a controller in such a way that responses for creation requests will not respond immediately with a representation of the created resource. " Class { - #name : #RESTfulControllerDoNotRespondCreatedEntityPolicy, - #superclass : #RESTfulControllerResourceCreationPolicy, + #name : 'RESTfulControllerDoNotRespondCreatedEntityPolicy', + #superclass : 'RESTfulControllerResourceCreationPolicy', #instVars : [ 'requestHandler' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RESTfulControllerDoNotRespondCreatedEntityPolicy class >> for: aRequestHandler [ ^ self new initializeFor: aRequestHandler ] -{ #category : #initialization } +{ #category : 'initialization' } RESTfulControllerDoNotRespondCreatedEntityPolicy >> initializeFor: aRequestHandler [ requestHandler := aRequestHandler ] -{ #category : #processing } +{ #category : 'processing' } RESTfulControllerDoNotRespondCreatedEntityPolicy >> responseFor: resource basedOn: httpRequest within: requestContext [ ^ ZnResponse created: ( requestHandler locationOf: resource within: requestContext ) diff --git a/source/Stargate-Model/RESTfulControllerPaginateCollectionsPolicy.class.st b/source/Stargate-Model/RESTfulControllerPaginateCollectionsPolicy.class.st index 7081e41..32ba8f9 100644 --- a/source/Stargate-Model/RESTfulControllerPaginateCollectionsPolicy.class.st +++ b/source/Stargate-Model/RESTfulControllerPaginateCollectionsPolicy.class.st @@ -2,28 +2,30 @@ I'm the policy indicating a RESTful controller to support pagination of collections related to the controlled resource. " Class { - #name : #RESTfulControllerPaginateCollectionsPolicy, - #superclass : #RESTfulControllerPaginationPolicy, + #name : 'RESTfulControllerPaginateCollectionsPolicy', + #superclass : 'RESTfulControllerPaginationPolicy', #instVars : [ 'defaultLimit', 'requestHandler' ], - #category : #'Stargate-Model-Pagination' + #category : 'Stargate-Model-Pagination', + #package : 'Stargate-Model', + #tag : 'Pagination' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RESTfulControllerPaginateCollectionsPolicy class >> for: aRequestHandler with: aPaginationLimit [ ^ self new initializeFor: aRequestHandler with: aPaginationLimit ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerPaginateCollectionsPolicy >> addPaginationControlsTo: mediaControls within: requestContext [ ^ mediaControls , requestContext paginationControls ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerPaginateCollectionsPolicy >> affect: response within: requestContext [ requestContext paginationControls do: [ :assoc | @@ -33,7 +35,7 @@ RESTfulControllerPaginateCollectionsPolicy >> affect: response within: requestCo ] ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerPaginateCollectionsPolicy >> evaluateQuery: aQueryEvaluationBlock basedOn: httpRequest [ | pagination | @@ -44,14 +46,14 @@ RESTfulControllerPaginateCollectionsPolicy >> evaluateQuery: aQueryEvaluationBlo ^ requestHandler evaluateCollectionQuery: [ aQueryEvaluationBlock cull: pagination ] ] -{ #category : #initialization } +{ #category : 'initialization' } RESTfulControllerPaginateCollectionsPolicy >> initializeFor: aRequestHandler with: aPaginationLimit [ requestHandler := aRequestHandler. defaultLimit := aPaginationLimit ] -{ #category : #private } +{ #category : 'private' } RESTfulControllerPaginateCollectionsPolicy >> paginationFrom: httpRequest [ ^ PaginationSpecification diff --git a/source/Stargate-Model/RESTfulControllerPaginationPolicy.class.st b/source/Stargate-Model/RESTfulControllerPaginationPolicy.class.st index dd95a59..c458f1f 100644 --- a/source/Stargate-Model/RESTfulControllerPaginationPolicy.class.st +++ b/source/Stargate-Model/RESTfulControllerPaginationPolicy.class.st @@ -2,24 +2,26 @@ I'm the policy used to control pagination in a RESTfulController " Class { - #name : #RESTfulControllerPaginationPolicy, - #superclass : #Object, - #category : #'Stargate-Model-Pagination' + #name : 'RESTfulControllerPaginationPolicy', + #superclass : 'Object', + #category : 'Stargate-Model-Pagination', + #package : 'Stargate-Model', + #tag : 'Pagination' } -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerPaginationPolicy >> addPaginationControlsTo: mediaControls within: httpRequest [ ^ self subclassResponsibility ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerPaginationPolicy >> affect: response within: requestContext [ self subclassResponsibility ] -{ #category : #applying } +{ #category : 'applying' } RESTfulControllerPaginationPolicy >> evaluateQuery: aQueryEvaluationBlock basedOn: httpRequest [ self subclassResponsibility diff --git a/source/Stargate-Model/RESTfulControllerResourceCreationPolicy.class.st b/source/Stargate-Model/RESTfulControllerResourceCreationPolicy.class.st index e5e656c..1a9c095 100644 --- a/source/Stargate-Model/RESTfulControllerResourceCreationPolicy.class.st +++ b/source/Stargate-Model/RESTfulControllerResourceCreationPolicy.class.st @@ -2,12 +2,14 @@ I'm an abstract policy controlling how to respond on the creation of new resources. " Class { - #name : #RESTfulControllerResourceCreationPolicy, - #superclass : #Object, - #category : #'Stargate-Model-Controllers' + #name : 'RESTfulControllerResourceCreationPolicy', + #superclass : 'Object', + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #processing } +{ #category : 'processing' } RESTfulControllerResourceCreationPolicy >> responseFor: resource basedOn: httpRequest within: requestContext [ self subclassResponsibility diff --git a/source/Stargate-Model/RESTfulControllerRespondCreatedEntityPolicy.class.st b/source/Stargate-Model/RESTfulControllerRespondCreatedEntityPolicy.class.st index df21a41..d8029e6 100644 --- a/source/Stargate-Model/RESTfulControllerRespondCreatedEntityPolicy.class.st +++ b/source/Stargate-Model/RESTfulControllerRespondCreatedEntityPolicy.class.st @@ -2,27 +2,29 @@ I'm a policy configuring a controller in such a way that responses for creation requests will respond immediately with a representation of the created resource. " Class { - #name : #RESTfulControllerRespondCreatedEntityPolicy, - #superclass : #RESTfulControllerResourceCreationPolicy, + #name : 'RESTfulControllerRespondCreatedEntityPolicy', + #superclass : 'RESTfulControllerResourceCreationPolicy', #instVars : [ 'requestHandler' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RESTfulControllerRespondCreatedEntityPolicy class >> for: aRequestHandler [ ^ self new initializeFor: aRequestHandler ] -{ #category : #initialization } +{ #category : 'initialization' } RESTfulControllerRespondCreatedEntityPolicy >> initializeFor: aRequestHandler [ requestHandler := aRequestHandler ] -{ #category : #processing } +{ #category : 'processing' } RESTfulControllerRespondCreatedEntityPolicy >> responseFor: resource basedOn: httpRequest within: requestContext [ | response | diff --git a/source/Stargate-Model/RESTfulRequestExceptionHandler.class.st b/source/Stargate-Model/RESTfulRequestExceptionHandler.class.st index 98676b3..136bbe2 100644 --- a/source/Stargate-Model/RESTfulRequestExceptionHandler.class.st +++ b/source/Stargate-Model/RESTfulRequestExceptionHandler.class.st @@ -2,21 +2,23 @@ I'm an exception handler to be used while handling a RESTful HTTP request " Class { - #name : #RESTfulRequestExceptionHandler, - #superclass : #Object, + #name : 'RESTfulRequestExceptionHandler', + #superclass : 'Object', #instVars : [ 'exceptionsToHandle' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestExceptionHandler >> addAsConflictError: anExceptionSelector [ exceptionsToHandle at: #conflict put: ( exceptionsToHandle at: #conflict ) , anExceptionSelector ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestExceptionHandler >> addAsDecodingError: anExceptionSelector [ exceptionsToHandle @@ -24,7 +26,7 @@ RESTfulRequestExceptionHandler >> addAsDecodingError: anExceptionSelector [ put: ( exceptionsToHandle at: #decodingFailed ) , anExceptionSelector ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestExceptionHandler >> addAsMissingQueryParameterError: anExceptionSelector [ exceptionsToHandle @@ -32,19 +34,19 @@ RESTfulRequestExceptionHandler >> addAsMissingQueryParameterError: anExceptionSe put: ( exceptionsToHandle at: #missingQueryParameters ) , anExceptionSelector ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestExceptionHandler >> addAsNotFoundError: anExceptionSelector [ exceptionsToHandle at: #notFound put: ( exceptionsToHandle at: #notFound ) , anExceptionSelector ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestExceptionHandler >> addAsUnprocessableEntityError: anExceptionSelector [ exceptionsToHandle at: #unprocessableEntity put: ( exceptionsToHandle at: #unprocessableEntity ) , anExceptionSelector ] -{ #category : #handling } +{ #category : 'handling' } RESTfulRequestExceptionHandler >> handleConflictsDuring: aBlock [ ^ aBlock @@ -52,7 +54,7 @@ RESTfulRequestExceptionHandler >> handleConflictsDuring: aBlock [ do: [ :signal | HTTPClientError conflict signal: signal messageText ] ] -{ #category : #handling } +{ #category : 'handling' } RESTfulRequestExceptionHandler >> handleDecodingFailedDuring: aBlock [ ^ [ @@ -64,7 +66,7 @@ RESTfulRequestExceptionHandler >> handleDecodingFailedDuring: aBlock [ do: [ :signal | HTTPClientError unprocessableEntity signal: signal messageText ] ] -{ #category : #handling } +{ #category : 'handling' } RESTfulRequestExceptionHandler >> handleMissingQueryParametersDuring: aBlock [ ^ aBlock @@ -72,13 +74,13 @@ RESTfulRequestExceptionHandler >> handleMissingQueryParametersDuring: aBlock [ do: [ :signal | HTTPClientError badRequest signal: signal messageText ] ] -{ #category : #handling } +{ #category : 'handling' } RESTfulRequestExceptionHandler >> handleNotFoundAndMissingParametersDuring: aBlock [ ^ self handleNotFoundDuring: [ self handleMissingQueryParametersDuring: aBlock ] ] -{ #category : #handling } +{ #category : 'handling' } RESTfulRequestExceptionHandler >> handleNotFoundDuring: aBlock [ ^ aBlock @@ -86,7 +88,7 @@ RESTfulRequestExceptionHandler >> handleNotFoundDuring: aBlock [ do: [ :signal | HTTPClientError notFound signal: signal messageText ] ] -{ #category : #initialization } +{ #category : 'initialization' } RESTfulRequestExceptionHandler >> initialize [ super initialize. diff --git a/source/Stargate-Model/RESTfulRequestHandler.class.st b/source/Stargate-Model/RESTfulRequestHandler.class.st index b667348..f474294 100644 --- a/source/Stargate-Model/RESTfulRequestHandler.class.st +++ b/source/Stargate-Model/RESTfulRequestHandler.class.st @@ -3,12 +3,14 @@ I represent a RESTful handler, and provide the base support to easily create spe I provide the standard machinery to handle REST requests, and I'm supposed to be used from a controller. " Class { - #name : #RESTfulRequestHandler, - #superclass : #RESTfulRequestHandlerBehavior, - #category : #'Stargate-Model-Controllers' + #name : 'RESTfulRequestHandler', + #superclass : 'RESTfulRequestHandlerBehavior', + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RESTfulRequestHandler class >> resourceLocator: aResouceLocator paginationPolicy: aPaginationPolicy decodingRules: theDecodingRules encodingRules: theEncodingRules calculateEntityTagsWith: entityTagCalculator cachingDirectives: theCachingDirectives allowedLanguageTags: allowedLanguageTags handleErrorsWith: anExceptionHandler [ ^ self new diff --git a/source/Stargate-Model/RESTfulRequestHandlerBehavior.class.st b/source/Stargate-Model/RESTfulRequestHandlerBehavior.class.st index 81156de..fd5a4c5 100644 --- a/source/Stargate-Model/RESTfulRequestHandlerBehavior.class.st +++ b/source/Stargate-Model/RESTfulRequestHandlerBehavior.class.st @@ -3,8 +3,8 @@ I represent a RESTful handler, and provide the base support to easily create spe I provide the standard machinery to handle REST requests, and I'm supposed to be used from a controller. " Class { - #name : #RESTfulRequestHandlerBehavior, - #superclass : #Object, + #name : 'RESTfulRequestHandlerBehavior', + #superclass : 'Object', #instVars : [ 'paginationPolicy', 'decodingRules', @@ -14,24 +14,26 @@ Class { 'acceptNegotiator', 'cachingDirectives' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> applyCachingDirectivesFor: aResource to: response within: requestContext [ cachingDirectives do: [ :directive | directive cull: response cull: requestContext cull: aResource ] ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> assert: etag matchesEntityTagOf: entity encodedAs: mediaType within: requestContext [ etag = ( self entityTagOf: entity encodedAs: mediaType within: requestContext ) ifFalse: [ HTTPClientError preconditionFailed signal ] ] -{ #category : #'decoding/encoding' } +{ #category : 'decoding/encoding' } RESTfulRequestHandlerBehavior >> decode: httpRequest within: requestContext [ | decodingRule | @@ -44,7 +46,7 @@ RESTfulRequestHandlerBehavior >> decode: httpRequest within: requestContext [ handleDecodingFailedDuring: [ decodingRule cull: httpRequest contents cull: requestContext ] ] -{ #category : #'decoding/encoding' } +{ #category : 'decoding/encoding' } RESTfulRequestHandlerBehavior >> encode: resource as: targetMediaType within: requestContext [ | encodingRule | @@ -55,7 +57,7 @@ RESTfulRequestHandlerBehavior >> encode: resource as: targetMediaType within: re ^ encodingRule encode: resource within: requestContext ] -{ #category : #'decoding/encoding' } +{ #category : 'decoding/encoding' } RESTfulRequestHandlerBehavior >> encode: resource within: requestContext [ ^ self @@ -64,13 +66,13 @@ RESTfulRequestHandlerBehavior >> encode: resource within: requestContext [ within: requestContext ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> encodeResource: resource as: mediaType within: requestContext [ ^ self encode: resource as: mediaType within: requestContext ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> encodeResource: resource within: requestContext [ ^ self @@ -79,19 +81,19 @@ RESTfulRequestHandlerBehavior >> encodeResource: resource within: requestContext within: requestContext ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> encodeResourceCollection: resourceCollection basedOn: httpRequest within: requestContext [ ^ self encode: resourceCollection within: requestContext ] -{ #category : #accessing } +{ #category : 'accessing' } RESTfulRequestHandlerBehavior >> endpoint [ ^ resourceLocator endpoint ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> entityTagOf: resource encodedAs: mediaType within: requestContext [ ^ EntityTag with: (entityTagCalculator @@ -101,7 +103,7 @@ RESTfulRequestHandlerBehavior >> entityTagOf: resource encodedAs: mediaType with value: self) ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> entityTagToMatchBasedOn: httpRequest [ ^ (httpRequest headers at: 'If-Match' ifAbsent: [ @@ -109,19 +111,19 @@ RESTfulRequestHandlerBehavior >> entityTagToMatchBasedOn: httpRequest [ 'Missing If-Match header.' ]) asEntityTag ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> evaluateCollectionQuery: aQueryEvaluationBlock [ ^ self exceptionHandler handleMissingQueryParametersDuring: aQueryEvaluationBlock ] -{ #category : #accessing } +{ #category : 'accessing' } RESTfulRequestHandlerBehavior >> exceptionHandler [ ^ resourceLocator exceptionHandler ] -{ #category : #API } +{ #category : 'API' } RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext get: aQueryEvaluationBlock [ | resource response | @@ -153,7 +155,7 @@ RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext get: a ^ response ] -{ #category : #API } +{ #category : 'API' } RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext get: aQueryEvaluationBlock thenDo: actionBlock [ | resource | @@ -165,7 +167,7 @@ RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext get: a ^ ZnResponse noContent ] -{ #category : #API } +{ #category : 'API' } RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext get: findBlock thenUpdateWith: updateBlock [ | etag | @@ -193,7 +195,7 @@ RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext get: f ] ] -{ #category : #API } +{ #category : 'API' } RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext getCollection: aQueryEvaluationBlock [ | resourceCollection encodedResourceCollection response | @@ -213,7 +215,7 @@ RESTfulRequestHandlerBehavior >> from: httpRequest within: requestContext getCol ^ response ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> holdTargetMediaTypeAndLanguageFrom: httpRequest within: requestContext [ httpRequest hasLanguageProrityList @@ -222,7 +224,7 @@ RESTfulRequestHandlerBehavior >> holdTargetMediaTypeAndLanguageFrom: httpRequest ^ requestContext targetMediaType: ( acceptNegotiator bestRepresentationFor: httpRequest ) ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> ifNoneMatchHeaderPresentIn: httpRequest do: aMonadycBlock [ httpRequest headers @@ -231,7 +233,7 @@ RESTfulRequestHandlerBehavior >> ifNoneMatchHeaderPresentIn: httpRequest do: aMo aMonadycBlock value: ifNoneMatchHeader asEntityTag ] ] -{ #category : #initialization } +{ #category : 'initialization' } RESTfulRequestHandlerBehavior >> initializeResourceLocator: aResouceLocator paginationPolicy: aPaginationPolicy decodingRules: theDecodingRules @@ -251,19 +253,19 @@ RESTfulRequestHandlerBehavior >> initializeResourceLocator: aResouceLocator cachingDirectives := theCachingDirectives ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> locationOf: resource within: requestContext [ ^ resourceLocator locationOf: resource within: requestContext ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> paginationPolicy [ ^ paginationPolicy ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> putEntityTagOf: resource in: response within: requestContext [ response @@ -271,7 +273,7 @@ RESTfulRequestHandlerBehavior >> putEntityTagOf: resource in: response within: r addToVary: 'Accept' ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> putLanguageContentTagIn: response within: requestContext [ requestContext @@ -282,7 +284,7 @@ RESTfulRequestHandlerBehavior >> putLanguageContentTagIn: response within: reque ] ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBehavior >> resourceCreationPolicyBasedOn: httpRequest within: requestContext [ ^ httpRequest @@ -293,19 +295,19 @@ RESTfulRequestHandlerBehavior >> resourceCreationPolicyBasedOn: httpRequest with ifAbsent: [ RESTfulControllerDoNotRespondCreatedEntityPolicy for: self ] ] -{ #category : #accessing } +{ #category : 'accessing' } RESTfulRequestHandlerBehavior >> resourceLocator [ ^ resourceLocator ] -{ #category : #accessing } +{ #category : 'accessing' } RESTfulRequestHandlerBehavior >> serverUrl: aServerUrl [ resourceLocator baseUrl: aServerUrl ] -{ #category : #API } +{ #category : 'API' } RESTfulRequestHandlerBehavior >> withRepresentationIn: httpRequest within: requestContext createResourceWith: aCreationBlock thenDo: aBlock [ ^ self @@ -317,7 +319,7 @@ RESTfulRequestHandlerBehavior >> withRepresentationIn: httpRequest within: reque ] ] -{ #category : #API } +{ #category : 'API' } RESTfulRequestHandlerBehavior >> withResourceCreatedFrom: httpRequest within: requestContext do: aBlock [ | creationPolicy decodedRepresentation newResource | diff --git a/source/Stargate-Model/RESTfulRequestHandlerBuilder.class.st b/source/Stargate-Model/RESTfulRequestHandlerBuilder.class.st index f577619..a77b3ea 100644 --- a/source/Stargate-Model/RESTfulRequestHandlerBuilder.class.st +++ b/source/Stargate-Model/RESTfulRequestHandlerBuilder.class.st @@ -2,8 +2,8 @@ I'm a builder of RESTful handlers " Class { - #name : #RESTfulRequestHandlerBuilder, - #superclass : #Object, + #name : 'RESTfulRequestHandlerBuilder', + #superclass : 'Object', #instVars : [ 'decodingRules', 'encodingRules', @@ -15,22 +15,24 @@ Class { 'cachingDirectives', 'allowedLanguageTags' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> addAsSupportedLanguage: aLanguageTag [ allowedLanguageTags add: aLanguageTag asLanguageTag ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> beHypermediaDriven [ self beHypermediaDrivenBy: [ ] ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> beHypermediaDrivenBy: aMediaControlsFactoryBlock [ AssertionChecker @@ -57,13 +59,13 @@ RESTfulRequestHandlerBuilder >> beHypermediaDrivenBy: aMediaControlsFactoryBlock ] ] -{ #category : #building } +{ #category : 'building' } RESTfulRequestHandlerBuilder >> build [ ^ handlerFactory value ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> createEntityTagHashing: aBlockClosure [ self @@ -77,7 +79,7 @@ RESTfulRequestHandlerBuilder >> createEntityTagHashing: aBlockClosure [ ] ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> createEntityTagHashingEncodedResource [ self @@ -88,19 +90,19 @@ RESTfulRequestHandlerBuilder >> createEntityTagHashingEncodedResource [ ] ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> createEntityTagWith: aBlock [ entityTagFactoryBinding := Binding to: aBlock ] -{ #category : #decoding } +{ #category : 'decoding' } RESTfulRequestHandlerBuilder >> decodeToNeoJSONObjectWhenAccepting: aMediaType [ self whenAccepting: aMediaType decodeApplying: [ :json | NeoJSONObject fromString: json ] ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> directCachingWith: aBlock [ cachingDirectives := CachingDirectivesBuilder new @@ -108,25 +110,25 @@ RESTfulRequestHandlerBuilder >> directCachingWith: aBlock [ build ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> handleExceptionsApplying: aBlock [ aBlock value: exceptionHandler ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> handling: anEndpoint [ resourceLocator := ResourceLocator handling: anEndpoint ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> handling: anEndpoint extractingIdentifierWith: aBlock [ resourceLocator := ResourceLocator handling: anEndpoint extractingIdentifierWith: aBlock ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> handling: anEndpoint extractingIdentifierWith: aBlock locatingParentResourceWith: aResourceLocator [ resourceLocator := SubresourceLocator @@ -135,7 +137,7 @@ RESTfulRequestHandlerBuilder >> handling: anEndpoint extractingIdentifierWith: a locatingParentResourceWith: aResourceLocator ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> handling: anEndpoint locatingResourcesWith: aLocationBlock extractingIdentifierWith: aBlock [ resourceLocator := ResourceLocator @@ -144,7 +146,7 @@ RESTfulRequestHandlerBuilder >> handling: anEndpoint locatingResourcesWith: aLoc andIdentifierBy: aBlock ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> handling: anEndpoint locatingSubresourcesWith: aLocationBlock extractingIdentifierWith: aBlock locatingParentResourceWith: aResourceLocator [ resourceLocator := SubresourceLocator @@ -154,7 +156,7 @@ RESTfulRequestHandlerBuilder >> handling: anEndpoint locatingSubresourcesWith: a locatingParentResourceWith: aResourceLocator ] -{ #category : #initialization } +{ #category : 'initialization' } RESTfulRequestHandlerBuilder >> initialize [ super initialize. @@ -177,7 +179,7 @@ RESTfulRequestHandlerBuilder >> initialize [ ] ] -{ #category : #private } +{ #category : 'private' } RESTfulRequestHandlerBuilder >> jsonFor: resource within: requestContext applying: aBlock writingResourceWith: aResourceWritingBlock [ ^ String streamContents: [ :stream | @@ -188,13 +190,13 @@ RESTfulRequestHandlerBuilder >> jsonFor: resource within: requestContext applyin ] ] -{ #category : #configuring } +{ #category : 'configuring' } RESTfulRequestHandlerBuilder >> paginateCollectionsWithDefaultLimit: anInteger [ paginationPolicyFactory := [ :processor | RESTfulControllerPaginateCollectionsPolicy for: processor with: anInteger ] ] -{ #category : #decoding } +{ #category : 'decoding' } RESTfulRequestHandlerBuilder >> whenAccepting: aMediaType decodeApplying: aDecodingBlock [ "aDecodingBlock will be evaluated with the request contents and optionally the request context" @@ -205,7 +207,7 @@ RESTfulRequestHandlerBuilder >> whenAccepting: aMediaType decodeApplying: aDecod ifAbsentPut: [ aDecodingBlock ] ] -{ #category : #decoding } +{ #category : 'decoding' } RESTfulRequestHandlerBuilder >> whenAccepting: aMediaType decodeFromJsonApplying: aBlock [ self @@ -213,7 +215,7 @@ RESTfulRequestHandlerBuilder >> whenAccepting: aMediaType decodeFromJsonApplying decodeApplying: [ :json | aBlock value: json value: ( NeoJSONReader on: json readStream ) ] ] -{ #category : #encoding } +{ #category : 'encoding' } RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeApplying: anEncodingBlock [ encodingRules @@ -222,7 +224,7 @@ RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeApplying: anEnc ifAbsentPut: [ ResourceEncodingRule encoding: aMediaType using: anEncodingBlock ] ] -{ #category : #encoding } +{ #category : 'encoding' } RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeToJsonApplying: aBlock [ self whenResponding: aMediaType encodeApplying: [ :resource :requestContext | @@ -242,7 +244,7 @@ RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeToJsonApplying: ] ] -{ #category : #encoding } +{ #category : 'encoding' } RESTfulRequestHandlerBuilder >> whenResponding: aMediaType encodeToJsonApplying: aBlock as: schema [ self whenResponding: aMediaType encodeApplying: [ :resource :requestContext | diff --git a/source/Stargate-Model/ReflectiveRoutesConfigurator.class.st b/source/Stargate-Model/ReflectiveRoutesConfigurator.class.st index 146b030..721015a 100644 --- a/source/Stargate-Model/ReflectiveRoutesConfigurator.class.st +++ b/source/Stargate-Model/ReflectiveRoutesConfigurator.class.st @@ -4,27 +4,29 @@ I'm a reflective configurator of web service routes. I'm being used to configure a Teapot server routes reflectively. I expect web service specification declare its routes on messages that follow the pattern #*Route " Class { - #name : #ReflectiveRoutesConfigurator, - #superclass : #Object, + #name : 'ReflectiveRoutesConfigurator', + #superclass : 'Object', #instVars : [ 'teapot' ], - #category : #'Stargate-Model-Routing' + #category : 'Stargate-Model-Routing', + #package : 'Stargate-Model', + #tag : 'Routing' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } ReflectiveRoutesConfigurator class >> appliedTo: aTeapot [ ^ self new initializeAppliedTo: aTeapot ] -{ #category : #configuring } +{ #category : 'configuring' } ReflectiveRoutesConfigurator >> addRoutesOf: aResourceRESTfulController [ (RouteConfigurator configuring: teapot withRoutesDefinedOn: aResourceRESTfulController) configure ] -{ #category : #initialization } +{ #category : 'initialization' } ReflectiveRoutesConfigurator >> initializeAppliedTo: aTeapot [ teapot := aTeapot diff --git a/source/Stargate-Model/ResourceCollection.class.st b/source/Stargate-Model/ResourceCollection.class.st index 8ad97e1..4d7ec03 100644 --- a/source/Stargate-Model/ResourceCollection.class.st +++ b/source/Stargate-Model/ResourceCollection.class.st @@ -5,27 +5,29 @@ I'm used internally in Hypermedia driven controllers to ease the media control c I'm not intended to be used externally. " Class { - #name : #ResourceCollection, - #superclass : #Object, + #name : 'ResourceCollection', + #superclass : 'Object', #instVars : [ 'items' ], - #category : #'Stargate-Model-HATEOAS' + #category : 'Stargate-Model-HATEOAS', + #package : 'Stargate-Model', + #tag : 'HATEOAS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } ResourceCollection class >> wrapping: aCollection [ ^self new initializeWrapping: aCollection ] -{ #category : #initialization } +{ #category : 'initialization' } ResourceCollection >> initializeWrapping: aCollection [ items := aCollection ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceCollection >> items [ ^ items diff --git a/source/Stargate-Model/ResourceEncodingRule.class.st b/source/Stargate-Model/ResourceEncodingRule.class.st index 9f35c34..7842079 100644 --- a/source/Stargate-Model/ResourceEncodingRule.class.st +++ b/source/Stargate-Model/ResourceEncodingRule.class.st @@ -3,28 +3,30 @@ I'm an encoding rule. I'm responsible of generating an Entity with the provided media type encoding a resource into it's representation. " Class { - #name : #ResourceEncodingRule, - #superclass : #Object, + #name : 'ResourceEncodingRule', + #superclass : 'Object', #instVars : [ 'mediaType', 'encodingBlock' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } ResourceEncodingRule class >> encoding: aMediaType using: aWriter [ ^ self new initializeMapping: aMediaType using: aWriter ] -{ #category : #encoding } +{ #category : 'encoding' } ResourceEncodingRule >> encode: resource within: requestContext [ ^ ZnEntity with: ( encodingBlock cull: resource cull: requestContext ) ofType: mediaType ] -{ #category : #initialization } +{ #category : 'initialization' } ResourceEncodingRule >> initializeMapping: aMediaType using: anEncodingBlock [ encodingBlock := anEncodingBlock. diff --git a/source/Stargate-Model/ResourceLocator.class.st b/source/Stargate-Model/ResourceLocator.class.st index 786ddc0..9b46506 100644 --- a/source/Stargate-Model/ResourceLocator.class.st +++ b/source/Stargate-Model/ResourceLocator.class.st @@ -2,8 +2,8 @@ I'm responsible for locating specific resource instances and generating location urls from them " Class { - #name : #ResourceLocator, - #superclass : #ResourceLocatorBehavior, + #name : 'ResourceLocator', + #superclass : 'ResourceLocatorBehavior', #instVars : [ 'baseUrl', 'endpoint', @@ -11,16 +11,18 @@ Class { 'locationResolverBinding', 'exceptionHandler' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } ResourceLocator class >> handling: aStringOrSymbol [ ^ self handling: aStringOrSymbol extractingIdentifierWith: [ :httpRequest | '' ] ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } ResourceLocator class >> handling: aStringOrSymbol calculatingLocationWith: aLocationResolver andIdentifierBy: aBlock [ ^ self @@ -29,7 +31,7 @@ ResourceLocator class >> handling: aStringOrSymbol calculatingLocationWith: aLoc andIdentifierBy: aBlock ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } ResourceLocator class >> handling: aStringOrSymbol extractingIdentifierWith: aBlock [ ^ self @@ -38,7 +40,7 @@ ResourceLocator class >> handling: aStringOrSymbol extractingIdentifierWith: aBl andIdentifierBy: aBlock ] -{ #category : #private } +{ #category : 'private' } ResourceLocator class >> handling: aStringOrSymbol resolvingLocationWith: aLocationResolverBinding andIdentifierBy: aBlock [ ^ self new @@ -47,49 +49,49 @@ ResourceLocator class >> handling: aStringOrSymbol resolvingLocationWith: aLocat andIdentifierBy: aBlock ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocator >> baseUrl [ ^ baseUrl ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocator >> baseUrl: aServerUrl [ baseUrl := aServerUrl asUrl ] -{ #category : #testing } +{ #category : 'testing' } ResourceLocator >> canLookupResources [ ^ locationResolverBinding isDefined ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocator >> endpoint [ ^ endpoint ] -{ #category : #private } +{ #category : 'private' } ResourceLocator >> exceptionHandler [ ^ exceptionHandler ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocator >> handleExceptionsWith: anExceptionHandler [ exceptionHandler := anExceptionHandler ] -{ #category : #private } +{ #category : 'private' } ResourceLocator >> identifierLookupAction [ ^ identifierLookupAction ] -{ #category : #initialization } +{ #category : 'initialization' } ResourceLocator >> initializeHandling: aStringOrSymbol resolvingLocationWith: aLocationResolverBinding andIdentifierBy: aBlock [ baseUrl := '' asUrl. @@ -99,7 +101,7 @@ ResourceLocator >> initializeHandling: aStringOrSymbol resolvingLocationWith: aL exceptionHandler := RESTfulRequestExceptionHandler new ] -{ #category : #querying } +{ #category : 'querying' } ResourceLocator >> locationOf: resource within: requestContext [ ^ self baseUrl / endpoint asUrl diff --git a/source/Stargate-Model/ResourceLocatorBehavior.class.st b/source/Stargate-Model/ResourceLocatorBehavior.class.st index 087dd45..5503ba1 100644 --- a/source/Stargate-Model/ResourceLocatorBehavior.class.st +++ b/source/Stargate-Model/ResourceLocatorBehavior.class.st @@ -1,58 +1,60 @@ Class { - #name : #ResourceLocatorBehavior, - #superclass : #Object, - #category : #'Stargate-Model-Controllers' + #name : 'ResourceLocatorBehavior', + #superclass : 'Object', + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocatorBehavior >> baseUrl [ ^ self subclassResponsibility ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocatorBehavior >> baseUrl: aServerUrl [ self subclassResponsibility ] -{ #category : #testing } +{ #category : 'testing' } ResourceLocatorBehavior >> canLookupResources [ self subclassResponsibility ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocatorBehavior >> endpoint [ ^ self subclassResponsibility ] -{ #category : #private } +{ #category : 'private' } ResourceLocatorBehavior >> exceptionHandler [ ^ self subclassResponsibility ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceLocatorBehavior >> handleExceptionsWith: anExceptionHandler [ self subclassResponsibility ] -{ #category : #private } +{ #category : 'private' } ResourceLocatorBehavior >> identifierLookupAction [ ^ self subclassResponsibility ] -{ #category : #querying } +{ #category : 'querying' } ResourceLocatorBehavior >> locationOf: resource within: requestContext [ self subclassResponsibility ] -{ #category : #querying } +{ #category : 'querying' } ResourceLocatorBehavior >> lookupResourceIdentifiedBy: httpRequest evaluating: aQueryBlock [ ^ self exceptionHandler diff --git a/source/Stargate-Model/ResourceRESTfulController.class.st b/source/Stargate-Model/ResourceRESTfulController.class.st index 4ec368f..95ac144 100644 --- a/source/Stargate-Model/ResourceRESTfulController.class.st +++ b/source/Stargate-Model/ResourceRESTfulController.class.st @@ -5,26 +5,28 @@ My subclasses must create one or more RESTfulRequestHandler (usually with the av and delegate to them the needed methods. " Class { - #name : #ResourceRESTfulController, - #superclass : #Object, - #category : #'Stargate-Model-Controllers' + #name : 'ResourceRESTfulController', + #superclass : 'Object', + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #testing } +{ #category : 'testing' } ResourceRESTfulController class >> isAbstract [ ^ self = ResourceRESTfulController ] -{ #category : #private } +{ #category : 'private' } ResourceRESTfulController >> jsonMediaType: aSubType vendoredBy: aVendorName version: aVersion [ ^ ( 'application/vnd.<1s>.<2s>+json' expandMacrosWith: aVendorName with: aSubType ) asMediaType version: aVersion ] -{ #category : #accessing } +{ #category : 'accessing' } ResourceRESTfulController >> routes [ ^ ( UnaryMessageSendingCollector @@ -33,7 +35,7 @@ ResourceRESTfulController >> routes [ to: self ) value ] -{ #category : #configuring } +{ #category : 'configuring' } ResourceRESTfulController >> serverUrl: aServerUrl [ self subclassResponsibility diff --git a/source/Stargate-Model/RouteConfigurator.class.st b/source/Stargate-Model/RouteConfigurator.class.st index f9a5f8f..fe7a5a7 100644 --- a/source/Stargate-Model/RouteConfigurator.class.st +++ b/source/Stargate-Model/RouteConfigurator.class.st @@ -4,29 +4,31 @@ I'm a web service route configurator. I'm being used to configure a route on a Teapot server. I also know how to configure a route supporting cross-origin resource sharing. " Class { - #name : #RouteConfigurator, - #superclass : #Object, + #name : 'RouteConfigurator', + #superclass : 'Object', #instVars : [ 'teapot', 'resourceController' ], - #category : #'Stargate-Model-Routing' + #category : 'Stargate-Model-Routing', + #package : 'Stargate-Model', + #tag : 'Routing' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RouteConfigurator class >> configuring: aTeapot withRoutesDefinedOn: aResourceRESTfulController [ ^ self new initializeConfiguring: aTeapot withRoutesDefinedOn: aResourceRESTfulController ] -{ #category : #configuring } +{ #category : 'configuring' } RouteConfigurator >> configure [ resourceController routes do: [ :routeSpecification | routeSpecification configureUsing: self ] ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } RouteConfigurator >> configureRouteFrom: aRouteSpecification [ teapot addRouteMatchedBy: aRouteSpecification asRequestMatcher action: [ :request | @@ -35,7 +37,7 @@ RouteConfigurator >> configureRouteFrom: aRouteSpecification [ ] ] -{ #category : #initialization } +{ #category : 'initialization' } RouteConfigurator >> initializeConfiguring: aTeapot withRoutesDefinedOn: aResourceRESTfulController [ teapot := aTeapot. @@ -43,7 +45,7 @@ RouteConfigurator >> initializeConfiguring: aTeapot withRoutesDefinedOn: aResour self withServerUrlDo: [ :url | resourceController serverUrl: url ]. ] -{ #category : #'private - configuring' } +{ #category : 'private - configuring' } RouteConfigurator >> withServerUrlDo: aBlock [ teapot server serverUrl ifNotNil: aBlock diff --git a/source/Stargate-Model/RouteSpecification.class.st b/source/Stargate-Model/RouteSpecification.class.st index ceaa436..ccb02bf 100644 --- a/source/Stargate-Model/RouteSpecification.class.st +++ b/source/Stargate-Model/RouteSpecification.class.st @@ -3,30 +3,32 @@ I'm an spec for a route. I provide a URL template, an HTTP method and a handler to invoke for this route. " Class { - #name : #RouteSpecification, - #superclass : #Object, + #name : 'RouteSpecification', + #superclass : 'Object', #instVars : [ 'httpMethod', 'handler', 'urlTemplate' ], - #category : #'Stargate-Model-Routing' + #category : 'Stargate-Model-Routing', + #package : 'Stargate-Model', + #tag : 'Routing' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } RouteSpecification class >> handling: anHttpMethod at: anUrlTemplate evaluating: aBlock [ ^ self new initializeHandling: anHttpMethod at: anUrlTemplate evaluating: aBlock ] -{ #category : #converting } +{ #category : 'converting' } RouteSpecification >> asRequestMatcher [ ^ TeaRequestMatcher method: ( TeaMethodMatcher exactly: httpMethod asSymbol ) url: urlTemplate asTeaUrlPattern ] -{ #category : #configuring } +{ #category : 'configuring' } RouteSpecification >> authenticatedBy: anAuthorizationFilter [ ^ self class @@ -38,25 +40,25 @@ RouteSpecification >> authenticatedBy: anAuthorizationFilter [ ] ] -{ #category : #configuring } +{ #category : 'configuring' } RouteSpecification >> configureUsing: aRouteConfigurator [ aRouteConfigurator configureRouteFrom: self ] -{ #category : #accessing } +{ #category : 'accessing' } RouteSpecification >> handler [ ^ handler ] -{ #category : #accessing } +{ #category : 'accessing' } RouteSpecification >> httpMethod [ ^ httpMethod ] -{ #category : #initialization } +{ #category : 'initialization' } RouteSpecification >> initializeHandling: anHttpMethod at: anURLTemplate evaluating: aBlock [ httpMethod := anHttpMethod. @@ -67,7 +69,7 @@ RouteSpecification >> initializeHandling: anHttpMethod at: anURLTemplate evaluat ] ] -{ #category : #accessing } +{ #category : 'accessing' } RouteSpecification >> urlTemplate [ ^ urlTemplate diff --git a/source/Stargate-Model/SingleResourceRESTfulController.class.st b/source/Stargate-Model/SingleResourceRESTfulController.class.st index 049a772..86d9811 100644 --- a/source/Stargate-Model/SingleResourceRESTfulController.class.st +++ b/source/Stargate-Model/SingleResourceRESTfulController.class.st @@ -2,37 +2,39 @@ I'm a RESTful controllers handling only one resource, so I can make some assumptions and provide some ready to use behavior. " Class { - #name : #SingleResourceRESTfulController, - #superclass : #ResourceRESTfulController, - #category : #'Stargate-Model-Controllers' + #name : 'SingleResourceRESTfulController', + #superclass : 'ResourceRESTfulController', + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #testing } +{ #category : 'testing' } SingleResourceRESTfulController class >> isAbstract [ ^ self = SingleResourceRESTfulController ] -{ #category : #private } +{ #category : 'private' } SingleResourceRESTfulController >> endpoint [ ^ self requestHandler endpoint ] -{ #category : #private } +{ #category : 'private' } SingleResourceRESTfulController >> identifierIn: httpRequest [ ^ httpRequest at: self identifierKey ] -{ #category : #private } +{ #category : 'private' } SingleResourceRESTfulController >> identifierKey [ ^ #identifier asString ] -{ #category : #private } +{ #category : 'private' } SingleResourceRESTfulController >> identifierTemplate [ ^ '<1s>/%<<2s>:<3s>>' @@ -41,19 +43,19 @@ SingleResourceRESTfulController >> identifierTemplate [ with: self typeIdConstraint asString ] -{ #category : #private } +{ #category : 'private' } SingleResourceRESTfulController >> requestHandler [ ^ self subclassResponsibility ] -{ #category : #configuring } +{ #category : 'configuring' } SingleResourceRESTfulController >> serverUrl: aServerUrl [ self requestHandler serverUrl: aServerUrl ] -{ #category : #private } +{ #category : 'private' } SingleResourceRESTfulController >> typeIdConstraint [ ^ self subclassResponsibility diff --git a/source/Stargate-Model/SubresourceLocator.class.st b/source/Stargate-Model/SubresourceLocator.class.st index 953a9d0..53482b3 100644 --- a/source/Stargate-Model/SubresourceLocator.class.st +++ b/source/Stargate-Model/SubresourceLocator.class.st @@ -2,8 +2,8 @@ I'm responsible for locating specific subresource instances and generating location urls from them " Class { - #name : #SubresourceLocator, - #superclass : #ResourceLocatorBehavior, + #name : 'SubresourceLocator', + #superclass : 'ResourceLocatorBehavior', #instVars : [ 'endpoint', 'identifierLookupAction', @@ -11,10 +11,12 @@ Class { 'resourceLocator', 'exceptionHandler' ], - #category : #'Stargate-Model-Controllers' + #category : 'Stargate-Model-Controllers', + #package : 'Stargate-Model', + #tag : 'Controllers' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } SubresourceLocator class >> handling: aStringOrSymbol calculatingLocationWith: aLocationResolver andIdentifierBy: aBlock @@ -27,7 +29,7 @@ SubresourceLocator class >> handling: aStringOrSymbol locatingParentResourceWith: aResourceLocator ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } SubresourceLocator class >> handling: aStringOrSymbol extractingIdentifierWith: aBlock locatingParentResourceWith: aResourceLocator [ ^ self @@ -37,7 +39,7 @@ SubresourceLocator class >> handling: aStringOrSymbol extractingIdentifierWith: locatingParentResourceWith: aResourceLocator ] -{ #category : #private } +{ #category : 'private' } SubresourceLocator class >> handling: aStringOrSymbol resolvingLocationWith: aLocationResolverBinding andIdentifierBy: aBlock @@ -50,49 +52,49 @@ SubresourceLocator class >> handling: aStringOrSymbol locatingParentResourceWith: aResourceLocator ] -{ #category : #accessing } +{ #category : 'accessing' } SubresourceLocator >> baseUrl [ ^ resourceLocator baseUrl ] -{ #category : #accessing } +{ #category : 'accessing' } SubresourceLocator >> baseUrl: aServerUrl [ resourceLocator baseUrl: aServerUrl ] -{ #category : #testing } +{ #category : 'testing' } SubresourceLocator >> canLookupResources [ ^ locationResolverBinding isDefined ] -{ #category : #accessing } +{ #category : 'accessing' } SubresourceLocator >> endpoint [ ^ endpoint ] -{ #category : #private } +{ #category : 'private' } SubresourceLocator >> exceptionHandler [ ^ exceptionHandler ] -{ #category : #accessing } +{ #category : 'accessing' } SubresourceLocator >> handleExceptionsWith: anExceptionHandler [ exceptionHandler := anExceptionHandler ] -{ #category : #private } +{ #category : 'private' } SubresourceLocator >> identifierLookupAction [ ^ identifierLookupAction ] -{ #category : #initialization } +{ #category : 'initialization' } SubresourceLocator >> initializeHandling: aStringOrSymbol resolvingLocationWith: aLocationResolverBinding andIdentifierBy: aBlock @@ -105,7 +107,7 @@ SubresourceLocator >> initializeHandling: aStringOrSymbol exceptionHandler := RESTfulRequestExceptionHandler new ] -{ #category : #querying } +{ #category : 'querying' } SubresourceLocator >> locationOf: resource within: requestContext [ ^ ( resourceLocator locationOf: requestContext parentResource within: requestContext ) diff --git a/source/Stargate-Model/WebOrigin.class.st b/source/Stargate-Model/WebOrigin.class.st index 7e10fa9..5b5cfd3 100644 --- a/source/Stargate-Model/WebOrigin.class.st +++ b/source/Stargate-Model/WebOrigin.class.st @@ -12,15 +12,17 @@ References https://tools.ietf.org/html/rfc3986 " Class { - #name : #WebOrigin, - #superclass : #Object, + #name : 'WebOrigin', + #superclass : 'Object', #instVars : [ 'url' ], - #category : #'Stargate-Model-CORS' + #category : 'Stargate-Model-CORS', + #package : 'Stargate-Model', + #tag : 'CORS' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } WebOrigin class >> basedOn: aUrl [ AssertionChecker @@ -31,7 +33,7 @@ WebOrigin class >> basedOn: aUrl [ ^ self new initializeBasedOn: aUrl ] -{ #category : #preconditions } +{ #category : 'preconditions' } WebOrigin class >> hasValidOrigin: aUrl [ | validOriginSchemes | @@ -41,43 +43,43 @@ WebOrigin class >> hasValidOrigin: aUrl [ ^ aUrl hasScheme and: [ ( validOriginSchemes includes: aUrl scheme ) and: [ aUrl hasHost ] ] ] -{ #category : #comparing } +{ #category : 'comparing' } WebOrigin >> = aWebOrigin [ ^ self asString = aWebOrigin asString ] -{ #category : #converting } +{ #category : 'converting' } WebOrigin >> asString [ ^ self printString ] -{ #category : #converting } +{ #category : 'converting' } WebOrigin >> asUrl [ ^ url copy ] -{ #category : #converting } +{ #category : 'converting' } WebOrigin >> asWebOrigin [ ^ self ] -{ #category : #comparing } +{ #category : 'comparing' } WebOrigin >> hash [ ^ self asString hash ] -{ #category : #initialization } +{ #category : 'initialization' } WebOrigin >> initializeBasedOn: aUrl [ url := aUrl ] -{ #category : #printing } +{ #category : 'printing' } WebOrigin >> printOn: stream [ stream diff --git a/source/Stargate-Model/ZnAuthenticationFilter.class.st b/source/Stargate-Model/ZnAuthenticationFilter.class.st index aadff24..f463efa 100644 --- a/source/Stargate-Model/ZnAuthenticationFilter.class.st +++ b/source/Stargate-Model/ZnAuthenticationFilter.class.st @@ -2,15 +2,17 @@ I'm an authentication filter supporting the already provided ZnAuthenticators: ZnBasicAuthenticator or ZnDigestAuthenticator " Class { - #name : #ZnAuthenticationFilter, - #superclass : #AuthenticationFilter, + #name : 'ZnAuthenticationFilter', + #superclass : 'AuthenticationFilter', #instVars : [ 'authenticator' ], - #category : #'Stargate-Model-Auth' + #category : 'Stargate-Model-Auth', + #package : 'Stargate-Model', + #tag : 'Auth' } -{ #category : #private } +{ #category : 'private' } ZnAuthenticationFilter class >> canHandle: configuration [ | schema | @@ -19,7 +21,7 @@ ZnAuthenticationFilter class >> canHandle: configuration [ ^ schema = 'basic' ] -{ #category : #private } +{ #category : 'private' } ZnAuthenticationFilter class >> configuredBy: configuration [ ^ self @@ -27,32 +29,32 @@ ZnAuthenticationFilter class >> configuredBy: configuration [ password: ( configuration at: #authPassword ifAbsent: [ AssertionFailed signal: 'Missing password' ] ) ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } ZnAuthenticationFilter class >> username: username password: password [ ^ self using: ( ZnBasicAuthenticator username: username password: password ) ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } ZnAuthenticationFilter class >> using: aZnAuthenticator [ ^ self new initializeUsing: aZnAuthenticator ] -{ #category : #accessing } +{ #category : 'accessing' } ZnAuthenticationFilter >> authChallenge [ ^ authenticator authHeader ] -{ #category : #private } +{ #category : 'private' } ZnAuthenticationFilter >> checkCredentials: authorization for: httpRequest within: requestContext ifInvalid: aBlock [ ( authenticator isRequestAuthenticated: httpRequest ) ifFalse: aBlock ] -{ #category : #initialization } +{ #category : 'initialization' } ZnAuthenticationFilter >> initializeUsing: anAuthenticator [ authenticator := anAuthenticator diff --git a/source/Stargate-Model/package.st b/source/Stargate-Model/package.st index 023767a..3b49133 100644 --- a/source/Stargate-Model/package.st +++ b/source/Stargate-Model/package.st @@ -1 +1 @@ -Package { #name : #'Stargate-Model' } +Package { #name : 'Stargate-Model' } diff --git a/source/Stargate-SUnit-Model/HTTPBasedRESTfulAPITest.class.st b/source/Stargate-SUnit-Model/HTTPBasedRESTfulAPITest.class.st index 9ef8681..faf256d 100644 --- a/source/Stargate-SUnit-Model/HTTPBasedRESTfulAPITest.class.st +++ b/source/Stargate-SUnit-Model/HTTPBasedRESTfulAPITest.class.st @@ -2,46 +2,53 @@ A HTTPBasedRESTfulAPITest is a test class for testing the behavior of HTTPBasedRESTfulAPI " Class { - #name : #HTTPBasedRESTfulAPITest, - #superclass : #TestCase, + #name : 'HTTPBasedRESTfulAPITest', + #superclass : 'TestCase', #instVars : [ 'api', 'port' ], - #category : #'Stargate-SUnit-Model' + #category : 'Stargate-SUnit-Model', + #package : 'Stargate-SUnit-Model' } -{ #category : #testing } +{ #category : 'testing' } HTTPBasedRESTfulAPITest class >> isAbstract [ ^ self name = #HTTPBasedRESTfulAPITest ] -{ #category : #running } +{ #category : 'running' } HTTPBasedRESTfulAPITest >> algorithmName [ ^ 'HS256' ] -{ #category : #private } +{ #category : 'private' } HTTPBasedRESTfulAPITest >> baseUrl [ ^ 'http://localhost' asUrl port: self port ] -{ #category : #private } +{ #category : 'private' } HTTPBasedRESTfulAPITest >> claimSet [ ^ JWTClaimsSet new ] -{ #category : #private } +{ #category : 'private' } HTTPBasedRESTfulAPITest >> controllersToInstall [ ^ self subclassResponsibility ] -{ #category : #private } +{ #category : 'running' } +HTTPBasedRESTfulAPITest >> globalErrorHandler [ + + ^ [ :error :request | self fail ] +] + +{ #category : 'private' } HTTPBasedRESTfulAPITest >> newClient [ ^ ZnClient new @@ -50,13 +57,13 @@ HTTPBasedRESTfulAPITest >> newClient [ yourself ] -{ #category : #private } +{ #category : 'private' } HTTPBasedRESTfulAPITest >> newJWTAuthorizedClient [ ^ self newJWTAuthorizedClientClaiming: self claimSet ] -{ #category : #private } +{ #category : 'private' } HTTPBasedRESTfulAPITest >> newJWTAuthorizedClientClaiming: aClaimSet [ | client jws | @@ -71,7 +78,7 @@ HTTPBasedRESTfulAPITest >> newJWTAuthorizedClientClaiming: aClaimSet [ ^ client ] -{ #category : #running } +{ #category : 'running' } HTTPBasedRESTfulAPITest >> operationsConfiguration [ ^ Dictionary new @@ -81,19 +88,19 @@ HTTPBasedRESTfulAPITest >> operationsConfiguration [ yourself ] -{ #category : #private } +{ #category : 'private' } HTTPBasedRESTfulAPITest >> port [ ^ port ] -{ #category : #running } +{ #category : 'running' } HTTPBasedRESTfulAPITest >> secret [ ^ 'secret' ] -{ #category : #running } +{ #category : 'running' } HTTPBasedRESTfulAPITest >> setUp [ super setUp. @@ -104,20 +111,20 @@ HTTPBasedRESTfulAPITest >> setUp [ start ] -{ #category : #running } +{ #category : 'running' } HTTPBasedRESTfulAPITest >> setUpAPI [ api := HTTPBasedRESTfulAPI - configuredBy: { + configuredBy: { ( #port -> self port ). ( #serverUrl -> self baseUrl ). ( #operations -> self operationsConfiguration ) } installing: self controllersToInstall. - api on: Error addErrorHandler: [ :error :request | self fail ] + api on: Error addErrorHandler: self globalErrorHandler ] -{ #category : #running } +{ #category : 'running' } HTTPBasedRESTfulAPITest >> tearDown [ api ifNotNil: [ api stop ]. @@ -125,7 +132,7 @@ HTTPBasedRESTfulAPITest >> tearDown [ super tearDown ] -{ #category : #private } +{ #category : 'private' } HTTPBasedRESTfulAPITest >> withJsonFromContentsIn: httpResponse do: aBlock [ aBlock value: (NeoJSONObject fromString: httpResponse contents) diff --git a/source/Stargate-SUnit-Model/OperationalPluginAPITest.class.st b/source/Stargate-SUnit-Model/OperationalPluginAPITest.class.st index 8447617..ec93f87 100644 --- a/source/Stargate-SUnit-Model/OperationalPluginAPITest.class.st +++ b/source/Stargate-SUnit-Model/OperationalPluginAPITest.class.st @@ -2,30 +2,31 @@ I'm an abstract test class providing facilities to test the API of Operational Plugins " Class { - #name : #OperationalPluginAPITest, - #superclass : #HTTPBasedRESTfulAPITest, - #category : #'Stargate-SUnit-Model' + #name : 'OperationalPluginAPITest', + #superclass : 'HTTPBasedRESTfulAPITest', + #category : 'Stargate-SUnit-Model', + #package : 'Stargate-SUnit-Model' } -{ #category : #testing } +{ #category : 'testing' } OperationalPluginAPITest class >> isAbstract [ ^ self name = #OperationalPluginAPITest ] -{ #category : #asserting } +{ #category : 'asserting' } OperationalPluginAPITest >> assertIsDisabled: anOperationPluginType [ self deny: ( api isEnabled: anOperationPluginType ) ] -{ #category : #asserting } +{ #category : 'asserting' } OperationalPluginAPITest >> assertIsEnabled: anOperationPluginType [ self assert: ( api isEnabled: anOperationPluginType ) ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> claimSet [ ^ super claimSet @@ -33,42 +34,42 @@ OperationalPluginAPITest >> claimSet [ yourself ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> controllersToInstall [ ^ Array with: self ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> newJWTAuthorizedClientLackingPermissions [ ^ self newJWTAuthorizedClientClaiming: super claimSet ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> operationsPluginsUrl [ ^ self operationsUrl / 'plugins' ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> operationsUrl [ ^ self baseUrl / 'operations' asUrl ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> requiredPermissions [ self subclassResponsibility ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> routes [ ^ #() ] -{ #category : #private } +{ #category : 'private' } OperationalPluginAPITest >> serverUrl: aUrl [ ] diff --git a/source/Stargate-SUnit-Model/OperationalPluginRESTfulControllerTest.class.st b/source/Stargate-SUnit-Model/OperationalPluginRESTfulControllerTest.class.st index d0ce56d..39efc2b 100644 --- a/source/Stargate-SUnit-Model/OperationalPluginRESTfulControllerTest.class.st +++ b/source/Stargate-SUnit-Model/OperationalPluginRESTfulControllerTest.class.st @@ -1,22 +1,23 @@ Class { - #name : #OperationalPluginRESTfulControllerTest, - #superclass : #SingleResourceRESTfulControllerTest, - #category : #'Stargate-SUnit-Model' + #name : 'OperationalPluginRESTfulControllerTest', + #superclass : 'SingleResourceRESTfulControllerTest', + #category : 'Stargate-SUnit-Model', + #package : 'Stargate-SUnit-Model' } -{ #category : #testing } +{ #category : 'testing' } OperationalPluginRESTfulControllerTest class >> isAbstract [ ^ self name = #OperationalPluginRESTfulControllerTest ] -{ #category : #'private - support' } +{ #category : 'private - support' } OperationalPluginRESTfulControllerTest >> baseUrl [ ^ 'https://api.example.com' asUrl ] -{ #category : #'private - support' } +{ #category : 'private - support' } OperationalPluginRESTfulControllerTest >> newHttpRequestContext [ ^ super newHttpRequestContext @@ -24,7 +25,7 @@ OperationalPluginRESTfulControllerTest >> newHttpRequestContext [ yourself ] -{ #category : #'private - support' } +{ #category : 'private - support' } OperationalPluginRESTfulControllerTest >> operationsConfiguration [ ^ Dictionary new diff --git a/source/Stargate-SUnit-Model/ResourceRESTfulControllerTest.class.st b/source/Stargate-SUnit-Model/ResourceRESTfulControllerTest.class.st index 50bf039..b24e057 100644 --- a/source/Stargate-SUnit-Model/ResourceRESTfulControllerTest.class.st +++ b/source/Stargate-SUnit-Model/ResourceRESTfulControllerTest.class.st @@ -2,27 +2,28 @@ I'm an abstract Test Case providing facililties to test RESTfulControllers " Class { - #name : #ResourceRESTfulControllerTest, - #superclass : #TestCase, + #name : 'ResourceRESTfulControllerTest', + #superclass : 'TestCase', #instVars : [ 'resourceController' ], - #category : #'Stargate-SUnit-Model' + #category : 'Stargate-SUnit-Model', + #package : 'Stargate-SUnit-Model' } -{ #category : #testing } +{ #category : 'testing' } ResourceRESTfulControllerTest class >> isAbstract [ ^ self name = #ResourceRESTfulControllerTest ] -{ #category : #'private - asserting' } +{ #category : 'private - asserting' } ResourceRESTfulControllerTest >> assertCachingDirectivesFor: response with: aString [ self assert: response cachingDirectives equals: aString ] -{ #category : #'private - asserting' } +{ #category : 'private - asserting' } ResourceRESTfulControllerTest >> assertExpiresHeaderFor: response with: aDuration [ | oneMinuteBeforeFourHours fourHoursInTheFuture expiresString | @@ -37,19 +38,19 @@ ResourceRESTfulControllerTest >> assertExpiresHeaderFor: response with: aDuratio assert: ( expiresString = oneMinuteBeforeFourHours or: [ expiresString = fourHoursInTheFuture ] ) ] -{ #category : #'private - support' } +{ #category : 'private - support' } ResourceRESTfulControllerTest >> baseUrl [ ^ self subclassResponsibility ] -{ #category : #'private - support' } +{ #category : 'private - support' } ResourceRESTfulControllerTest >> newHttpRequestContext [ ^ HttpRequestContext new ] -{ #category : #running } +{ #category : 'running' } ResourceRESTfulControllerTest >> setUp [ super setUp. @@ -57,19 +58,19 @@ ResourceRESTfulControllerTest >> setUp [ resourceController serverUrl: self baseUrl asZnUrl ] -{ #category : #running } +{ #category : 'running' } ResourceRESTfulControllerTest >> setUpResourceController [ self subclassResponsibility ] -{ #category : #'private - support' } +{ #category : 'private - support' } ResourceRESTfulControllerTest >> withJsonFromContentsIn: httpResponse do: aBlock [ aBlock value: (NeoJSONObject fromString: httpResponse contents) ] -{ #category : #'private - support' } +{ #category : 'private - support' } ResourceRESTfulControllerTest >> withJsonFromItemsIn: httpResponse do: aBlock [ self withJsonFromContentsIn: httpResponse do: [:json | aBlock value: json items] diff --git a/source/Stargate-SUnit-Model/SingleResourceRESTfulControllerTest.class.st b/source/Stargate-SUnit-Model/SingleResourceRESTfulControllerTest.class.st index fb9a4e4..634a1b9 100644 --- a/source/Stargate-SUnit-Model/SingleResourceRESTfulControllerTest.class.st +++ b/source/Stargate-SUnit-Model/SingleResourceRESTfulControllerTest.class.st @@ -2,24 +2,25 @@ I'm an abstract Test Case providing facililties to test RESTfulControllers for single resources " Class { - #name : #SingleResourceRESTfulControllerTest, - #superclass : #ResourceRESTfulControllerTest, - #category : #'Stargate-SUnit-Model' + #name : 'SingleResourceRESTfulControllerTest', + #superclass : 'ResourceRESTfulControllerTest', + #category : 'Stargate-SUnit-Model', + #package : 'Stargate-SUnit-Model' } -{ #category : #testing } +{ #category : 'testing' } SingleResourceRESTfulControllerTest class >> isAbstract [ ^ self name = #SingleResourceRESTfulControllerTest ] -{ #category : #'private - support' } +{ #category : 'private - support' } SingleResourceRESTfulControllerTest >> endpoint [ ^ resourceController endpoint ] -{ #category : #'private - support' } +{ #category : 'private - support' } SingleResourceRESTfulControllerTest >> parametersWith: anIdentifier [ ^ SmallDictionary new @@ -27,7 +28,7 @@ SingleResourceRESTfulControllerTest >> parametersWith: anIdentifier [ yourself ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToDELETEResourceIdentifiedBy: anIdentifier [ ^ TeaRequest @@ -35,7 +36,7 @@ SingleResourceRESTfulControllerTest >> requestToDELETEResourceIdentifiedBy: anId pathParams: ( self parametersWith: anIdentifier ) ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGET: aUrl accepting: aMediaRange [ ^ self @@ -43,7 +44,7 @@ SingleResourceRESTfulControllerTest >> requestToGET: aUrl accepting: aMediaRange applying: [ :request | request setAccept: aMediaRange ] ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGET: aUrl applying: aConfiguration [ ^ self @@ -52,7 +53,7 @@ SingleResourceRESTfulControllerTest >> requestToGET: aUrl applying: aConfigurati applying: aConfiguration ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGET: aUrl withPathParams: aDictionary applying: aConfiguration [ | request | @@ -66,7 +67,7 @@ SingleResourceRESTfulControllerTest >> requestToGET: aUrl withPathParams: aDicti pathParams: aDictionary. ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGETResourceFrom: aLocation identifiedBy: anIdentifier applying: aConfiguration [ ^ self @@ -75,7 +76,7 @@ SingleResourceRESTfulControllerTest >> requestToGETResourceFrom: aLocation ident applying: aConfiguration ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdentifier accepting: aMediaRange [ ^ self @@ -83,7 +84,7 @@ SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdent applying: [ :request | request setAccept: aMediaRange ] ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdentifier accepting: aMediaRange conditionalTo: anETag [ ^ self @@ -94,7 +95,7 @@ SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdent setIfNoneMatchTo: anETag ] ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdentifier acceptingContentMatching: aMediaRange inAnyOf: aLanguageRange [ ^ self @@ -105,7 +106,7 @@ SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdent setAcceptLanguage: aLanguageRange ] ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdentifier applying: aConfiguration [ ^ self @@ -115,7 +116,7 @@ SingleResourceRESTfulControllerTest >> requestToGETResourceIdentifiedBy: anIdent applying: aConfiguration ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToGETSubresource: aSubresourceUrl identifiedBy: anIdentifier accepting: aMediaRange [ ^ self @@ -124,7 +125,7 @@ SingleResourceRESTfulControllerTest >> requestToGETSubresource: aSubresourceUrl applying: [ :request | request setAccept: aMediaRange ] ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToPATCHResourceIdentifiedBy: anIdentifier with: aRequestBody accepting: aMediaRange conditionalTo: anETag [ ^ TeaRequest @@ -137,7 +138,7 @@ SingleResourceRESTfulControllerTest >> requestToPATCHResourceIdentifiedBy: anIde pathParams: ( self parametersWith: anIdentifier ) ] -{ #category : #'private - HTTP requests' } +{ #category : 'private - HTTP requests' } SingleResourceRESTfulControllerTest >> requestToPOST: content as: aMediaType [ ^ TeaRequest @@ -147,13 +148,13 @@ SingleResourceRESTfulControllerTest >> requestToPOST: content as: aMediaType [ yourself) ] -{ #category : #'private - support' } +{ #category : 'private - support' } SingleResourceRESTfulControllerTest >> resourceUrl [ ^ self baseUrl / self endpoint ] -{ #category : #'private - support' } +{ #category : 'private - support' } SingleResourceRESTfulControllerTest >> urlForResourceIdentifiedBy: anIdentifier [ ^ self resourceUrl / anIdentifier asString asUrl diff --git a/source/Stargate-SUnit-Model/package.st b/source/Stargate-SUnit-Model/package.st index d7f487b..952698e 100644 --- a/source/Stargate-SUnit-Model/package.st +++ b/source/Stargate-SUnit-Model/package.st @@ -1 +1 @@ -Package { #name : #'Stargate-SUnit-Model' } +Package { #name : 'Stargate-SUnit-Model' } From c045270934a2db159043d9b8cd6d0a49b0739c60 Mon Sep 17 00:00:00 2001 From: Gabriel Cotelli Date: Wed, 22 Nov 2023 11:47:07 -0300 Subject: [PATCH 2/2] Improve code coverage --- .../ErroneousAPITest.class.st | 20 +++++++++---------- .../ErroneousRESTfulController.class.st | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/source/Stargate-Examples-Tests/ErroneousAPITest.class.st b/source/Stargate-Examples-Tests/ErroneousAPITest.class.st index c12495a..4456953 100644 --- a/source/Stargate-Examples-Tests/ErroneousAPITest.class.st +++ b/source/Stargate-Examples-Tests/ErroneousAPITest.class.st @@ -50,7 +50,7 @@ ErroneousAPITest >> testCORSAllowingAnyOrigin [ api allowCrossOriginSharingApplying: [ :cors | cors allowAnyOrigin ]. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; options; @@ -64,7 +64,7 @@ ErroneousAPITest >> testCORSAllowingAnyOrigin [ response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; enforceHttpSuccess: false; get; @@ -84,7 +84,7 @@ ErroneousAPITest >> testCORSAllowingExactlyOneOrigin [ api allowCrossOriginSharingApplying: [ :cors | cors allowOnlyFrom: { self baseUrl } ]. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; options; @@ -99,7 +99,7 @@ ErroneousAPITest >> testCORSAllowingExactlyOneOrigin [ assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'GET'. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; enforceHttpSuccess: false; get; @@ -124,7 +124,7 @@ ErroneousAPITest >> testCORSAllowingMoreThanOneOrigin [ ]. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; options; @@ -139,7 +139,7 @@ ErroneousAPITest >> testCORSAllowingMoreThanOneOrigin [ assert: ( response headers at: 'Access-Control-Allow-Methods' ) equals: 'GET'. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; enforceHttpSuccess: false; get; @@ -166,7 +166,7 @@ ErroneousAPITest >> testCORSOptionalHeaders [ ]. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; options; @@ -184,7 +184,7 @@ ErroneousAPITest >> testCORSOptionalHeaders [ assert: response varyHeaderNames includes: 'Access-Control-Allow-Headers'. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; enforceHttpSuccess: false; get; @@ -210,7 +210,7 @@ ErroneousAPITest >> testCORSRespondWithEmptyHeadersIfOriginNotAllowed [ api allowCrossOriginSharingApplying: [ :cors | cors allowOnlyFrom: { 'https://google.com' asUrl } ]. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; headerAt: 'Access-Control-Request-Headers' put: 'Content-Type'; options; @@ -223,7 +223,7 @@ ErroneousAPITest >> testCORSRespondWithEmptyHeadersIfOriginNotAllowed [ should: [ response headers at: 'Access-Control-Allow-Methods' ] raise: KeyNotFound. response := self newClient - url: self baseUrl / 'errors' asUrl; + url: self baseUrl / 'errors' / '1' asUrl; headerAt: 'Origin' put: self baseUrl printString; enforceHttpSuccess: false; get; diff --git a/source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st b/source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st index 4e27ce1..6c1c3e5 100644 --- a/source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st +++ b/source/Stargate-Examples-Tests/ErroneousRESTfulController.class.st @@ -13,9 +13,9 @@ Class { ErroneousRESTfulController >> declareGetErroneousRoute [ ^ RouteSpecification - handling: #GET - at: self endpoint - evaluating: [ :httpRequest :requestContext | Error signal: 'Server error' ] + handling: #GET + at: self identifierTemplate + evaluating: [ :httpRequest :requestContext | Error signal: 'Server error' ] ] { #category : 'initialization' }