@@ -21,6 +21,7 @@ import grails.converters.JSON
2121import grails.converters.XML
2222import grails.test.mixin.*
2323
24+ import net.hedtech.restfulapi.apiversioning.BasicApiVersionParser
2425import net.hedtech.restfulapi.config.*
2526import net.hedtech.restfulapi.extractors.*
2627import net.hedtech.restfulapi.extractors.configuration.*
@@ -2160,11 +2161,11 @@ class RestfulApiControllerSpec extends Specification {
21602161 unsupportedMediaTypeMethods = [' application/vnd.hedtech.v0+json' : [' create' ,' update' ,' delete' ],
21612162 ' application/vnd.hedtech.v1+json' : [' delete' ]]
21622163 representation {
2164+ mediaTypes = [' application/vnd.hedtech.v0+json' ,
2165+ ' application/vnd.hedtech.v1+json' ,
2166+ ' application/vnd.hedtech.v2+json' ]
21632167 representationMetadata = [filters : [" filter1" , " filter2" ]]
21642168 marshallers {
2165- mediaTypes = [' application/vnd.hedtech.v0+json' ,
2166- ' application/vnd.hedtech.v1+json' ,
2167- ' application/vnd.hedtech.v2+json' ]
21682169 jsonBeanMarshaller {}
21692170 }
21702171 jsonExtractor {}
@@ -2264,6 +2265,131 @@ class RestfulApiControllerSpec extends Specification {
22642265 ' delete' | ' application/json' | ' application/vnd.hedtech.v1+json' | false | true | []
22652266 }
22662267
2268+ @Unroll
2269+ def " Test API Versioning" () {
2270+ setup :
2271+ config. restfulApiConfig =
2272+ {
2273+ resource ' things' config {
2274+ methods = [' list' , ' show' , ' create' , ' update' , ' delete' ]
2275+ representation {
2276+ mediaTypes = [' application/vnd.hedtech.v1+json' ,
2277+ ' application/vnd.hedtech.v2+json' ,
2278+ ' application/vnd.hedtech+json' ]
2279+ marshallers {
2280+ jsonBeanMarshaller {}
2281+ }
2282+ jsonExtractor {}
2283+ }
2284+ representation {
2285+ mediaTypes = [' application/vnd.hedtech.v3.0.0+json' ,
2286+ ' application/vnd.hedtech.v3.1.0+json' ,
2287+ ' application/json' ]
2288+ marshallers {
2289+ jsonBeanMarshaller {}
2290+ }
2291+ jsonExtractor {}
2292+ }
2293+ representation {
2294+ mediaTypes = [' application/vnd.hedtech.custom+json' ]
2295+ marshallers {
2296+ jsonBeanMarshaller {}
2297+ }
2298+ jsonExtractor {}
2299+ }
2300+ }
2301+ }
2302+ defineBeans {
2303+ apiVersionParser(BasicApiVersionParser )
2304+ }
2305+ def genericMediaTypeList = [' application/json' , ' application/vnd.hedtech+json' , ' application/vnd.hedtech.custom+json' ]
2306+ if (override) {
2307+ controller. metaClass. getOverrideGenericMediaType = {-> override}
2308+ controller. metaClass. getGenericMediaTypeList = {-> genericMediaTypeList}
2309+ }
2310+ controller. init()
2311+
2312+ def mock = Mock (ThingService )
2313+ mock. list(_) >> { serviceReturn }
2314+ mock. count(_) >> { serviceReturn. size() }
2315+ mock. show(_) >> { serviceReturn }
2316+ mock. create(_,_) >> { serviceReturn }
2317+ mock. update(_,_) >> { serviceReturn }
2318+ mock. delete(_,_) >> {}
2319+ controller. metaClass. getService = {-> mock}
2320+ mockCacheHeaders()
2321+ params. pluralizedResourceName = ' things'
2322+ params. id = 1
2323+ def httpMethod = calculateHttpMethod(controllerMethod)
2324+
2325+ when :
2326+ request. addHeader(' Accept' , mediaType)
2327+ request. addHeader(' Content-Type' , mediaType)
2328+ request. method = httpMethod
2329+ controller. " $controllerMethod " ()
2330+
2331+ then :
2332+ (controllerMethod == ' create' ? 201 : 200 ) == response. status
2333+ mediaTypeHeader == response. getHeader(' X-hedtech-Media-Type' )
2334+ apiVersion == request. getAttribute(RepresentationRequestAttributes . RESPONSE_REPRESENTATION )?. apiVersion?. version
2335+ (httpMethod == ' GET' ? null : apiVersion) == request. getAttribute(RepresentationRequestAttributes . REQUEST_REPRESENTATION )?. apiVersion?. version
2336+
2337+ where :
2338+ controllerMethod | serviceReturn | override | mediaType | apiVersion | mediaTypeHeader
2339+ ' list' | [' foo' ] | false | ' application/json' | null | ' application/json'
2340+ ' show' | [name :' foo' ] | false | ' application/json' | null | ' application/json'
2341+ ' create' | [name :' foo' ] | false | ' application/json' | null | ' application/json'
2342+ ' update' | [name :' foo' ] | false | ' application/json' | null | ' application/json'
2343+ ' delete' | null | false | ' application/json' | null | null
2344+ // test override=true with generic mediaType=application/json
2345+ ' list' | [' foo' ] | true | ' application/json' | ' v3.1.0' | ' application/vnd.hedtech.v3.1.0+json'
2346+ ' show' | [name :' foo' ] | true | ' application/json' | ' v3.1.0' | ' application/vnd.hedtech.v3.1.0+json'
2347+ ' create' | [name :' foo' ] | true | ' application/json' | ' v3.1.0' | ' application/vnd.hedtech.v3.1.0+json'
2348+ ' update' | [name :' foo' ] | true | ' application/json' | ' v3.1.0' | ' application/vnd.hedtech.v3.1.0+json'
2349+ ' delete' | null | true | ' application/json' | null | null
2350+ // test override=true with generic mediaType=application/vnd.hedtech+json
2351+ ' list' | [' foo' ] | true | ' application/vnd.hedtech+json' | ' v2' | ' application/vnd.hedtech.v2+json'
2352+ ' show' | [name :' foo' ] | true | ' application/vnd.hedtech+json' | ' v2' | ' application/vnd.hedtech.v2+json'
2353+ ' create' | [name :' foo' ] | true | ' application/vnd.hedtech+json' | ' v2' | ' application/vnd.hedtech.v2+json'
2354+ ' update' | [name :' foo' ] | true | ' application/vnd.hedtech+json' | ' v2' | ' application/vnd.hedtech.v2+json'
2355+ ' delete' | null | true | ' application/vnd.hedtech+json' | null | null
2356+ // test override=true with generic mediaType=application/vnd.hedtech.custom+json
2357+ ' list' | [' foo' ] | true | ' application/vnd.hedtech.custom+json' | null | ' application/vnd.hedtech.custom+json'
2358+ ' show' | [name :' foo' ] | true | ' application/vnd.hedtech.custom+json' | null | ' application/vnd.hedtech.custom+json'
2359+ ' create' | [name :' foo' ] | true | ' application/vnd.hedtech.custom+json' | null | ' application/vnd.hedtech.custom+json'
2360+ ' update' | [name :' foo' ] | true | ' application/vnd.hedtech.custom+json' | null | ' application/vnd.hedtech.custom+json'
2361+ ' delete' | null | true | ' application/vnd.hedtech.custom+json' | null | null
2362+ // test override=true with actual mediaType=application/vnd.hedtech.v1+json
2363+ ' list' | [' foo' ] | true | ' application/vnd.hedtech.v1+json' | ' v1' | ' application/vnd.hedtech.v1+json'
2364+ ' show' | [name :' foo' ] | true | ' application/vnd.hedtech.v1+json' | ' v1' | ' application/vnd.hedtech.v1+json'
2365+ ' create' | [name :' foo' ] | true | ' application/vnd.hedtech.v1+json' | ' v1' | ' application/vnd.hedtech.v1+json'
2366+ ' update' | [name :' foo' ] | true | ' application/vnd.hedtech.v1+json' | ' v1' | ' application/vnd.hedtech.v1+json'
2367+ ' delete' | null | true | ' application/vnd.hedtech.v1+json' | null | null
2368+ }
2369+
2370+ private calculateHttpMethod (String controllerMethod ) {
2371+ def httpMethod
2372+ switch (controllerMethod) {
2373+ case ' list' :
2374+ httpMethod = ' GET'
2375+ break
2376+ case ' show' :
2377+ httpMethod = ' GET'
2378+ break
2379+ case ' create' :
2380+ httpMethod = ' POST'
2381+ break
2382+ case ' update' :
2383+ httpMethod = ' PUT'
2384+ break
2385+ case ' delete' :
2386+ httpMethod = ' DELETE'
2387+ break
2388+ default :
2389+ fail (" Unable to set request.method based on controllerMethod: " + controllerMethod)
2390+ }
2391+ return httpMethod
2392+ }
22672393
22682394 private void mockCacheHeaders () {
22692395 def cacheHeadersService = new CacheHeadersService ()
0 commit comments