From 9257034608ef39dc433ea044c83037d773c91335 Mon Sep 17 00:00:00 2001 From: Tianyuan Zhang Date: Tue, 8 Aug 2017 18:06:59 -0500 Subject: [PATCH] Allow header accept field to be evaluated. --- .../yahoo/bard/webservice/web/ApiRequest.java | 39 ++++++++++++++++--- .../bard/webservice/web/DataApiRequest.java | 4 +- .../webservice/web/DimensionsApiRequest.java | 4 +- .../bard/webservice/web/JobsApiRequest.java | 4 +- .../webservice/web/MetricsApiRequest.java | 4 +- .../bard/webservice/web/SlicesApiRequest.java | 4 +- .../bard/webservice/web/TablesApiRequest.java | 8 +++- .../webservice/web/endpoints/DataServlet.java | 1 + .../web/endpoints/DimensionsServlet.java | 3 ++ .../web/endpoints/FeatureFlagsServlet.java | 36 ++++++++++++++--- .../webservice/web/endpoints/JobsServlet.java | 3 ++ .../web/endpoints/MetricsServlet.java | 11 +++++- .../web/endpoints/SlicesServlet.java | 2 + .../web/endpoints/TablesServlet.java | 3 ++ .../query/WeightEvaluationQuerySpec.groovy | 4 ++ .../bard/webservice/web/ApiRequestSpec.groovy | 11 ++++-- .../webservice/web/DataApiRequestSpec.groovy | 13 ++++--- .../web/DimensionApiRequestMapperSpec.groovy | 3 ++ .../web/DimensionsApiRequestSpec.groovy | 4 ++ .../webservice/web/JobsApiRequestSpec.groovy | 2 + .../web/MetricsApiRequestSpec.groovy | 3 ++ .../web/SlicesApiRequestSpec.groovy | 3 ++ .../web/TableFullViewProcessorSpec.groovy | 2 +- .../web/TablesApiRequestSpec.groovy | 4 ++ ...ReactiveChainforResultsEndpointSpec.groovy | 19 ++++++++- 25 files changed, 163 insertions(+), 31 deletions(-) diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/ApiRequest.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/ApiRequest.java index d01bbf903e..245de4abd7 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/ApiRequest.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/ApiRequest.java @@ -48,6 +48,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -101,6 +102,7 @@ public abstract class ApiRequest { * Parses the API request URL and generates the API request object. * * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param asyncAfter How long the user is willing to wait for a synchronous request in milliseconds, if null * defaults to the system config {@code default_asyncAfter} * @param perPage number of rows to display per page of results. If present in the original request, must be a @@ -113,13 +115,14 @@ public abstract class ApiRequest { */ public ApiRequest( String format, + String headerFormat, String asyncAfter, @NotNull String perPage, @NotNull String page, UriInfo uriInfo ) throws BadApiRequestException { this.uriInfo = uriInfo; - this.format = generateAcceptFormat(format); + this.format = generateAcceptFormat(format, headerFormat); this.paginationParameters = generatePaginationParameters(perPage, page); this.builder = Response.status(Response.Status.OK); this.asyncAfter = generateAsyncAfter( @@ -134,6 +137,7 @@ public ApiRequest( * Parses the API request URL and generates the API request object. Defaults asyncAfter to never. * * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param perPage number of rows to display per page of results. If present in the original request, must be a * positive integer. If not present, must be the empty string. * @param page desired page of results. If present in the original request, must be a positive integer. If not @@ -144,11 +148,12 @@ public ApiRequest( */ public ApiRequest( String format, + final String headerFormat, @NotNull String perPage, @NotNull String page, UriInfo uriInfo ) throws BadApiRequestException { - this(format, SYNCHRONOUS_REQUEST_FLAG, perPage, page, uriInfo); + this(format, headerFormat , SYNCHRONOUS_REQUEST_FLAG, perPage, page, uriInfo); } /** @@ -588,15 +593,37 @@ protected Map> generateFilters( * Generates the format in which the response data is expected. * * @param format Expects a URL format query String. + * @param headerFormatString The accept field from http request header * * @return Response format type (CSV or JSON). * @throws BadApiRequestException if the requested format is not found. */ - protected ResponseFormatType generateAcceptFormat(String format) throws BadApiRequestException { + protected ResponseFormatType generateAcceptFormat( + String format, + final String headerFormatString + ) throws BadApiRequestException { try { - return format == null ? - ResponseFormatType.JSON : - ResponseFormatType.valueOf(format.toUpperCase(Locale.ENGLISH)); + String headerFormat = null; + if (headerFormatString != null) { + Map acceptFormats = new HashMap<>(); + acceptFormats.put("application/json", "json"); + acceptFormats.put("application/vnd.api+json", "jsonapi"); + acceptFormats.put("text/csv", "csv"); + for (String acceptFormat : acceptFormats.keySet()) { + if (headerFormatString.contains(acceptFormat)) { + headerFormat = acceptFormats.get(acceptFormat); + break; + } + } + } + + if (format != null) { + return ResponseFormatType.valueOf(format.toUpperCase(Locale.ENGLISH)); + } else if (headerFormat != null) { + return ResponseFormatType.valueOf(headerFormat.toUpperCase(Locale.ENGLISH)); + } else { + return ResponseFormatType.JSON; + } } catch (IllegalArgumentException e) { LOG.error(ACCEPT_FORMAT_INVALID.logFormat(format), e); throw new BadApiRequestException(ACCEPT_FORMAT_INVALID.format(format)); diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/DataApiRequest.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/DataApiRequest.java index aeb81eddf9..b2ab8292f1 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/DataApiRequest.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/DataApiRequest.java @@ -127,6 +127,7 @@ public class DataApiRequest extends ApiRequest { * @param count count of number of records to be returned in the response * @param topN number of first records per time bucket to be returned in the response * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param timeZoneId a joda time zone id * @param asyncAfter How long the user is willing to wait for a synchronous request in milliseconds * @param perPage number of rows to display per page of results. If present in the original request, @@ -162,6 +163,7 @@ public DataApiRequest( String count, String topN, String format, + String headerFormat, String timeZoneId, String asyncAfter, @NotNull String perPage, @@ -169,7 +171,7 @@ public DataApiRequest( UriInfo uriInfo, BardConfigResources bardConfigResources ) throws BadApiRequestException { - super(format, asyncAfter, perPage, page, uriInfo); + super(format, headerFormat, asyncAfter, perPage, page, uriInfo); GranularityParser granularityParser = bardConfigResources.getGranularityParser(); DimensionDictionary dimensionDictionary = bardConfigResources.getDimensionDictionary(); diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/DimensionsApiRequest.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/DimensionsApiRequest.java index 833d8411d5..5158e840ef 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/DimensionsApiRequest.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/DimensionsApiRequest.java @@ -45,6 +45,7 @@ public class DimensionsApiRequest extends ApiRequest { * ((field name and operation):((multiple values bounded by [])or(single value))))(followed by , or end of string) * } * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param perPage number of rows to display per page of results. If present in the original request, * must be a positive integer. If not present, must be the empty string. * @param page desired page of results. If present in the original request, must be a positive @@ -64,12 +65,13 @@ public DimensionsApiRequest( String dimension, String filters, String format, + String headerFormat, @NotNull String perPage, @NotNull String page, DimensionDictionary dimensionDictionary, UriInfo uriInfo ) throws BadApiRequestException { - super(format, perPage, page, uriInfo); + super(format, headerFormat, perPage, page, uriInfo); // Zero or more grouping dimensions may be specified this.dimensions = generateDimensions(dimension, dimensionDictionary); diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/JobsApiRequest.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/JobsApiRequest.java index 49bc418593..f5c875b67a 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/JobsApiRequest.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/JobsApiRequest.java @@ -36,6 +36,7 @@ public class JobsApiRequest extends ApiRequest { * Parses the API request URL and generates the Api Request object. * * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param asyncAfter How long the user is willing to wait for a synchronous request in milliseconds * @param perPage number of rows to display per page of results. If present in the original request, * must be a positive integer. If not present, must be the empty string. @@ -51,6 +52,7 @@ public class JobsApiRequest extends ApiRequest { */ public JobsApiRequest( String format, + String headerFormat, String asyncAfter, @NotNull String perPage, @NotNull String page, @@ -59,7 +61,7 @@ public JobsApiRequest( JobPayloadBuilder jobPayloadBuilder, ApiJobStore apiJobStore ) { - super(format, asyncAfter, perPage, page, uriInfo); + super(format, headerFormat, asyncAfter, perPage, page, uriInfo); this.jobPayloadBuilder = jobPayloadBuilder; this.apiJobStore = apiJobStore; this.filters = filters; diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/MetricsApiRequest.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/MetricsApiRequest.java index c0fc91ac7d..4704c24a92 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/MetricsApiRequest.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/MetricsApiRequest.java @@ -35,6 +35,7 @@ public class MetricsApiRequest extends ApiRequest { * ((field name and operation):((multiple values bounded by [])or(single value))))(followed by , or end of string) * } * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param perPage number of rows to display per page of results. If present in the original request, * must be a positive integer. If not present, must be the empty string. * @param page desired page of results. If present in the original request, must be a positive @@ -51,12 +52,13 @@ public class MetricsApiRequest extends ApiRequest { public MetricsApiRequest( String metricName, String format, + final String headerFormat, @NotNull String perPage, @NotNull String page, MetricDictionary metricDictionary, UriInfo uriInfo ) throws BadApiRequestException { - super(format, perPage, page, uriInfo); + super(format, headerFormat, perPage, page, uriInfo); this.metrics = generateMetrics(metricName, metricDictionary); diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/SlicesApiRequest.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/SlicesApiRequest.java index 86d2706d8b..ae7c8fdbdb 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/SlicesApiRequest.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/SlicesApiRequest.java @@ -49,6 +49,7 @@ public class SlicesApiRequest extends ApiRequest { * ((field name and operation):((multiple values bounded by [])or(single value))))(followed by , or end of string) * } * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param perPage number of rows to display per page of results. If present in the original request, * must be a positive integer. If not present, must be the empty string. * @param page desired page of results. If present in the original request, must be a positive @@ -66,13 +67,14 @@ public class SlicesApiRequest extends ApiRequest { public SlicesApiRequest( String sliceName, String format, + String headerFormat, @NotNull String perPage, @NotNull String page, PhysicalTableDictionary tableDictionary, DataSourceMetadataService dataSourceMetadataService, UriInfo uriInfo ) throws BadApiRequestException { - super(format, perPage, page, uriInfo); + super(format, headerFormat, perPage, page, uriInfo); this.slices = generateSlices(tableDictionary, uriInfo); this.slice = sliceName != null ? generateSlice( diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/TablesApiRequest.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/TablesApiRequest.java index f41460a074..c6a35eae10 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/TablesApiRequest.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/TablesApiRequest.java @@ -61,6 +61,7 @@ public class TablesApiRequest extends ApiRequest { * ((field name and operation):((multiple values bounded by [])or(single value))))(followed by , or end of string) * } * @param format response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param perPage number of rows to display per page of results. If present in the original request, * must be a positive integer. If not present, must be the empty string. * @param page desired page of results. If present in the original request, must be a positive @@ -78,12 +79,13 @@ public TablesApiRequest( String tableName, String granularity, String format, + String headerFormat, @NotNull String perPage, @NotNull String page, UriInfo uriInfo, BardConfigResources bardConfigResources ) throws BadApiRequestException { - super(format, perPage, page, uriInfo); + super(format, headerFormat, perPage, page, uriInfo); this.tables = generateTables(tableName, bardConfigResources.getLogicalTableDictionary()); @@ -121,6 +123,7 @@ public TablesApiRequest( * @param tableName Logical table corresponding to the table name specified in the URL * @param granularity Requested time granularity * @param format Response data format JSON or CSV. Default is JSON. + * @param headerFormat The accept field from http request header * @param perPage Number of rows to display per page of results. It must represent a positive integer or an empty * string if it's not specified * @param page Desired page of results. It must represent a positive integer or an empty @@ -143,6 +146,7 @@ public TablesApiRequest( String tableName, String granularity, String format, + final String headerFormat, @NotNull String perPage, @NotNull String page, UriInfo uriInfo, @@ -153,7 +157,7 @@ public TablesApiRequest( String filters, String timeZoneId ) throws BadApiRequestException { - super(format, perPage, page, uriInfo); + super(format, headerFormat, perPage, page, uriInfo); LogicalTableDictionary logicalTableDictionary = bardConfigResources.getLogicalTableDictionary(); this.tables = generateTables(tableName, logicalTableDictionary); diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DataServlet.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DataServlet.java index 00716f5178..9e5f8fe30d 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DataServlet.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DataServlet.java @@ -366,6 +366,7 @@ public void getData( count, topN, format, + containerRequestContext.getHeaderString("Accept"), timeZone, asyncAfter, perPage, diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DimensionsServlet.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DimensionsServlet.java index 5055223b5b..b6dbd8b7a1 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DimensionsServlet.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/DimensionsServlet.java @@ -122,6 +122,7 @@ public Response getAllDimensions( null, null, format, + containerRequestContext.getHeaderString("Accept"), perPage, page, dimensionDictionary, @@ -184,6 +185,7 @@ public Response getDimension( dimensionName, null, null, + containerRequestContext.getHeaderString("Accept"), "", "", dimensionDictionary, @@ -271,6 +273,7 @@ public Response getDimensionRows( dimensionName, filterQuery, format, + containerRequestContext.getHeaderString("Accept"), perPage, page, dimensionDictionary, diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/FeatureFlagsServlet.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/FeatureFlagsServlet.java index 1f30656edf..7c5224f114 100644 --- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/FeatureFlagsServlet.java +++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/FeatureFlagsServlet.java @@ -32,6 +32,7 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; +import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @@ -66,12 +67,19 @@ class FeatureFlagApiRequest extends ApiRequest { * Constructor. * * @param format Format of the request + * @param headerFormat The accept field from http request header * @param perPage How many items to show per page * @param page Which page to show * @param uriInfo URL information about the request */ - FeatureFlagApiRequest(String format, String perPage, String page, UriInfo uriInfo) { - super(format, perPage, page, uriInfo); + FeatureFlagApiRequest( + String format, + final String headerFormat, + String perPage, + String page, + UriInfo uriInfo + ) { + super(format, headerFormat, perPage, page, uriInfo); } } @@ -101,6 +109,7 @@ class FeatureFlagEntry { * @param page the page to start from * @param format the format to use * @param uriInfo the injected UriInfo + * @param containerRequestContext Context from the http request object * * @return Response Format: *

@@ -121,13 +130,20 @@ public Response getFeatureFlagStatusAll(
             @DefaultValue("") @NotNull @QueryParam("perPage") String perPage,
             @DefaultValue("") @NotNull @QueryParam("page") String page,
             @QueryParam("format") String format,
-            @Context UriInfo uriInfo
+            @Context UriInfo uriInfo,
+            @Context final ContainerRequestContext containerRequestContext
     ) {
         try {
             RequestLog.startTiming(this);
             RequestLog.record(new FeatureFlagRequest("all"));
 
-            FeatureFlagApiRequest apiRequest = new FeatureFlagApiRequest(format, perPage, page, uriInfo);
+            FeatureFlagApiRequest apiRequest = new FeatureFlagApiRequest(
+                    format,
+                    containerRequestContext.getHeaderString("Accept"),
+                    perPage,
+                    page,
+                    uriInfo
+            );
 
             List status = flags.getValues().stream()
                     .map(flag -> new FeatureFlagEntry(flag.getName(), flag.isOn()))
@@ -158,6 +174,7 @@ public Response getFeatureFlagStatusAll(
      * @param flagName The feature flag
      * @param format  The format to return results in
      * @param uriInfo  The injected UriInfo
+     * @param containerRequestContext Context from the http request object
      *
      * @return Response Format:
      * 

@@ -176,13 +193,20 @@ public Response getFeatureFlagStatusAll(
     public Response getFeatureFlagStatus(
             @PathParam("flagName") String flagName,
             @QueryParam("format") String format,
-            @Context UriInfo uriInfo
+            @Context UriInfo uriInfo,
+            @Context final ContainerRequestContext containerRequestContext
     ) {
         try {
             RequestLog.startTiming(this);
             RequestLog.record(new FeatureFlagRequest(flagName));
 
-            FeatureFlagApiRequest apiRequest = new FeatureFlagApiRequest(format, "", "", uriInfo);
+            FeatureFlagApiRequest apiRequest = new FeatureFlagApiRequest(
+                    format,
+                    containerRequestContext.getHeaderString("Accept"),
+                    "",
+                    "",
+                    uriInfo
+            );
 
             FeatureFlag flag = flags.forName(flagName);
             FeatureFlagEntry status = new FeatureFlagEntry(flag.getName(), flag.isOn());
diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/JobsServlet.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/JobsServlet.java
index 066a3315d9..6df7780e77 100644
--- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/JobsServlet.java
+++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/JobsServlet.java
@@ -152,6 +152,7 @@ public void getJobs(
 
             JobsApiRequest apiRequest = new JobsApiRequest (
                     format,
+                    containerRequestContext.getHeaderString("Accept"),
                     null, //asyncAfter is null so it behaves like a synchronous request
                     perPage,
                     page,
@@ -222,6 +223,7 @@ public void getJobByTicket(
             RequestLog.record(new JobRequest(ticket));
             JobsApiRequest apiRequest = new JobsApiRequest (
                     ResponseFormatType.JSON.toString(),
+                    containerRequestContext.getHeaderString("Accept"),
                     null,
                     "",
                     "",
@@ -280,6 +282,7 @@ public void getJobResultsByTicket(
 
             JobsApiRequest apiRequest = new JobsApiRequest (
                     format,
+                    containerRequestContext.getHeaderString("Accept"),
                     asyncAfter,
                     perPage,
                     page,
diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/MetricsServlet.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/MetricsServlet.java
index ed89ab6fdc..e4b5abdf07 100644
--- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/MetricsServlet.java
+++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/MetricsServlet.java
@@ -113,6 +113,7 @@ public Response getAllLogicalMetrics(
             MetricsApiRequest apiRequest = new MetricsApiRequest(
                     null,
                     format,
+                    containerRequestContext.getHeaderString("Accept"),
                     perPage,
                     page,
                     metricDictionary,
@@ -176,7 +177,15 @@ public Response getMetric(
             RequestLog.startTiming(this);
             RequestLog.record(new MetricRequest(metricName));
 
-            MetricsApiRequest apiRequest = new MetricsApiRequest(metricName, null, "", "", metricDictionary, uriInfo);
+            MetricsApiRequest apiRequest = new MetricsApiRequest(
+                    metricName,
+                    null,
+                    containerRequestContext.getHeaderString("Accept"),
+                    "",
+                    "",
+                    metricDictionary,
+                    uriInfo
+            );
 
             if (requestMapper != null) {
                 apiRequest = (MetricsApiRequest) requestMapper.apply(apiRequest, containerRequestContext);
diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/SlicesServlet.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/SlicesServlet.java
index cc4771b1b5..bc9e436f1b 100644
--- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/SlicesServlet.java
+++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/SlicesServlet.java
@@ -111,6 +111,7 @@ public Response getSlices(
             SlicesApiRequest apiRequest = new SlicesApiRequest(
                     null,
                     format,
+                    containerRequestContext.getHeaderString("Accept"),
                     perPage,
                     page,
                     physicalTableDictionary,
@@ -192,6 +193,7 @@ public Response getSliceBySliceName(
             SlicesApiRequest apiRequest = new SlicesApiRequest(
                     sliceName,
                     null,
+                    containerRequestContext.getHeaderString("Accept"),
                     "",
                     "",
                     physicalTableDictionary,
diff --git a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/TablesServlet.java b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/TablesServlet.java
index 8f6fe986ae..8b4ec7e88b 100644
--- a/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/TablesServlet.java
+++ b/fili-core/src/main/java/com/yahoo/bard/webservice/web/endpoints/TablesServlet.java
@@ -160,6 +160,7 @@ public Response getTable(
                     tableName,
                     null,
                     format,
+                    containerRequestContext.getHeaderString("Accept"),
                     perPage,
                     page,
                     uriInfo,
@@ -224,6 +225,7 @@ public Response getTableByGrain(
                     tableName,
                     grain,
                     null,
+                    containerRequestContext.getHeaderString("Accept"),
                     "",
                     "",
                     uriInfo,
@@ -281,6 +283,7 @@ public Response getTablesFullView(
                     null,
                     null,
                     null,
+                    containerRequestContext.getHeaderString("Accept"),
                     perPage,
                     page,
                     uriInfo,
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/druid/model/query/WeightEvaluationQuerySpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/druid/model/query/WeightEvaluationQuerySpec.groovy
index c8f6d69ce7..a3aa14d65e 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/druid/model/query/WeightEvaluationQuerySpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/druid/model/query/WeightEvaluationQuerySpec.groovy
@@ -114,6 +114,7 @@ class WeightEvaluationQuerySpec extends Specification {
                 null, //counts
                 null, //topN
                 null, //format
+                null, //header format
                 null, //timeZoneId
                 null, //asyncAfter
                 "", //perPage
@@ -143,6 +144,7 @@ class WeightEvaluationQuerySpec extends Specification {
                 null, //counts
                 null, //topN
                 null, //format
+                null, //header format
                 null, //timeZoneId
                 null, //asyncAfter
                 "", //perPage
@@ -171,6 +173,7 @@ class WeightEvaluationQuerySpec extends Specification {
                 null, //counts
                 null, //topN
                 null, //format
+                null, //header format
                 null, //timeZoneId
                 null, //asyncAfter
                 "", //perPage
@@ -199,6 +202,7 @@ class WeightEvaluationQuerySpec extends Specification {
                 null, //counts
                 null, //topN
                 null, //format
+                null, //header format
                 null, //timeZoneId
                 null, //asyncAfter
                 "", //perPage
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/ApiRequestSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/ApiRequestSpec.groovy
index 7d23341818..f52fe12066 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/ApiRequestSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/ApiRequestSpec.groovy
@@ -88,14 +88,17 @@ class ApiRequestSpec extends Specification {
 
         where:
         responseFormat          | expectedFormat
-        ResponseFormatType.JSON | new ConcreteApiRequest().generateAcceptFormat(null)
-        ResponseFormatType.JSON | new ConcreteApiRequest().generateAcceptFormat("json")
-        ResponseFormatType.CSV  | new ConcreteApiRequest().generateAcceptFormat("csv")
+        ResponseFormatType.JSON     | new DataApiRequest().generateAcceptFormat(null, null)
+        ResponseFormatType.JSON     | new DataApiRequest().generateAcceptFormat("json", null)
+        ResponseFormatType.JSON     | new DataApiRequest().generateAcceptFormat(null, "application/json")
+        ResponseFormatType.CSV      | new DataApiRequest().generateAcceptFormat("csv", null)
+        ResponseFormatType.CSV      | new DataApiRequest().generateAcceptFormat(null, "text/csv")
+        ResponseFormatType.JSONAPI  | new DataApiRequest().generateAcceptFormat(null, "application/vnd.api+json")
     }
 
     def "check invalid parsing generateFormat"() {
         when:
-        new ConcreteApiRequest().generateAcceptFormat("bad")
+        new ConcreteApiRequest().generateAcceptFormat("bad", null)
 
         then:
         thrown BadApiRequestException
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DataApiRequestSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DataApiRequestSpec.groovy
index dc304f5232..7a5fcebc4b 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DataApiRequestSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DataApiRequestSpec.groovy
@@ -86,15 +86,18 @@ class DataApiRequestSpec extends Specification {
         responseFormat == expectedFormat
 
         where:
-        responseFormat          | expectedFormat
-        ResponseFormatType.JSON | new DataApiRequest().generateAcceptFormat(null)
-        ResponseFormatType.JSON | new DataApiRequest().generateAcceptFormat("json")
-        ResponseFormatType.CSV  | new DataApiRequest().generateAcceptFormat("csv")
+        responseFormat              | expectedFormat
+        ResponseFormatType.JSON     | new DataApiRequest().generateAcceptFormat(null, null)
+        ResponseFormatType.JSON     | new DataApiRequest().generateAcceptFormat("json", null)
+        ResponseFormatType.JSON     | new DataApiRequest().generateAcceptFormat(null, "application/json")
+        ResponseFormatType.CSV      | new DataApiRequest().generateAcceptFormat("csv", null)
+        ResponseFormatType.CSV      | new DataApiRequest().generateAcceptFormat(null, "text/csv")
+        ResponseFormatType.JSONAPI  | new DataApiRequest().generateAcceptFormat(null, "application/vnd.api+json")
     }
 
     def "check invalid parsing generateFormat"() {
         when:
-        new DataApiRequest().generateAcceptFormat("bad")
+        new DataApiRequest().generateAcceptFormat("bad", null)
 
         then:
         thrown BadApiRequestException
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionApiRequestMapperSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionApiRequestMapperSpec.groovy
index 3b2f5b5d62..cc4bae80c1 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionApiRequestMapperSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionApiRequestMapperSpec.groovy
@@ -33,6 +33,7 @@ class DimensionApiRequestMapperSpec extends Specification {
                 "color",
                 "shape|desc-in[shape]",
                 null,
+                null,
                 "",
                 "",
                 resourceDictionaries.getDimensionDictionary(),
@@ -49,6 +50,7 @@ class DimensionApiRequestMapperSpec extends Specification {
                 "color",
                 "shape|desc-in[shape],color|desc-in[red]",
                 null,
+                null,
                 "",
                 "",
                 resourceDictionaries.getDimensionDictionary(),
@@ -65,6 +67,7 @@ class DimensionApiRequestMapperSpec extends Specification {
                 "color",
                 "color|desc-in[red]",
                 null,
+                null,
                 "",
                 "",
                 resourceDictionaries.getDimensionDictionary(),
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionsApiRequestSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionsApiRequestSpec.groovy
index 6007a99753..9f9e3f6aee 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionsApiRequestSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/DimensionsApiRequestSpec.groovy
@@ -35,6 +35,7 @@ class DimensionsApiRequestSpec extends Specification {
                 null,
                 null,
                 null,
+                null,
                 "",
                 "",
                 fullDictionary,
@@ -54,6 +55,7 @@ class DimensionsApiRequestSpec extends Specification {
                 name,
                 null,
                 null,
+                null,
                 "",
                 "",
                 fullDictionary,
@@ -75,6 +77,7 @@ class DimensionsApiRequestSpec extends Specification {
                 name,
                 filterString,
                 null,
+                null,
                 "",
                 "",
                 fullDictionary,
@@ -93,6 +96,7 @@ class DimensionsApiRequestSpec extends Specification {
                 name,
                 filter,
                 null,
+                null,
                 "",
                 "",
                 dictionary,
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/JobsApiRequestSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/JobsApiRequestSpec.groovy
index adac7bbd25..d7c7d5f871 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/JobsApiRequestSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/JobsApiRequestSpec.groovy
@@ -72,6 +72,7 @@ class JobsApiRequestSpec extends Specification {
         broadcastChannel = new SimpleBroadcastChannel<>(PublishSubject.create())
 
         defaultJobsApiRequest = new JobsApiRequest(
+                null,
                 null,
                 null,
                 "",
@@ -204,6 +205,7 @@ class JobsApiRequestSpec extends Specification {
         apiJobStore.save(userFooJobRow3)
 
         JobsApiRequest apiRequest = new JobsApiRequest(
+                null,
                 null,
                 null,
                 "",
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/MetricsApiRequestSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/MetricsApiRequestSpec.groovy
index fd030e4aad..098b5242e5 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/MetricsApiRequestSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/MetricsApiRequestSpec.groovy
@@ -32,6 +32,7 @@ class MetricsApiRequestSpec extends Specification {
     def "check api request construction for the top level endpoint (all tables)"() {
         when:
         MetricsApiRequest apiRequest = new MetricsApiRequest(
+                null,
                 null,
                 null,
                 "",
@@ -52,6 +53,7 @@ class MetricsApiRequestSpec extends Specification {
         MetricsApiRequest apiRequest = new MetricsApiRequest(
                 name,
                 null,
+                null,
                 "",
                 "",
                 fullDictionary,
@@ -68,6 +70,7 @@ class MetricsApiRequestSpec extends Specification {
         new MetricsApiRequest(
                 name,
                 null,
+                null,
                 "",
                 "",
                 dictionary,
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/SlicesApiRequestSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/SlicesApiRequestSpec.groovy
index 874ea61cea..1a5c624bb5 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/SlicesApiRequestSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/SlicesApiRequestSpec.groovy
@@ -65,6 +65,7 @@ class SlicesApiRequestSpec extends BaseDataSourceMetadataSpec {
 
         when:
         SlicesApiRequest apiRequest = new SlicesApiRequest(
+                null,
                 null,
                 null,
                 "",
@@ -121,6 +122,7 @@ class SlicesApiRequestSpec extends BaseDataSourceMetadataSpec {
         SlicesApiRequest apiRequest = new SlicesApiRequest(
                 name,
                 null,
+                null,
                 "",
                 "",
                 fullDictionary,
@@ -143,6 +145,7 @@ class SlicesApiRequestSpec extends BaseDataSourceMetadataSpec {
         new SlicesApiRequest(
                 name,
                 null,
+                null,
                 "",
                 "",
                 dictionary,
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TableFullViewProcessorSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TableFullViewProcessorSpec.groovy
index 012fd45cb8..14af1063bd 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TableFullViewProcessorSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TableFullViewProcessorSpec.groovy
@@ -43,7 +43,7 @@ class TableFullViewProcessorSpec extends Specification {
 
         TablesServlet tablesServlet = Mock(TablesServlet)
         tablesServlet.getLogicalTableDictionary() >> fullDictionary
-        TablesApiRequest apiRequest = new TablesApiRequest(null, null, null, "", "", null, tablesServlet)
+        TablesApiRequest apiRequest = new TablesApiRequest(null, null, null, null, "", "", null, tablesServlet)
         Set logicalTableSet = apiRequest.getTables();
 
         petsShapesTables= new HashSet<>()
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TablesApiRequestSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TablesApiRequestSpec.groovy
index dfd2f43295..c99d0bce04 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TablesApiRequestSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/TablesApiRequestSpec.groovy
@@ -48,6 +48,7 @@ class TablesApiRequestSpec extends Specification {
                 null,
                 null,
                 null,
+                null,
                 "",
                 "",
                 null,
@@ -69,6 +70,7 @@ class TablesApiRequestSpec extends Specification {
                 name,
                 null,
                 null,
+                null,
                 "",
                 "",
                 null,
@@ -93,6 +95,7 @@ class TablesApiRequestSpec extends Specification {
                 name,
                 "day",
                 null,
+                null,
                 "",
                 "",
                 null,
@@ -112,6 +115,7 @@ class TablesApiRequestSpec extends Specification {
                 name,
                 grain,
                 null,
+                null,
                 "",
                 "",
                 null,
diff --git a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/endpoints/JobsServletReactiveChainforResultsEndpointSpec.groovy b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/endpoints/JobsServletReactiveChainforResultsEndpointSpec.groovy
index f7d867e18e..b3804bec9d 100644
--- a/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/endpoints/JobsServletReactiveChainforResultsEndpointSpec.groovy
+++ b/fili-core/src/test/groovy/com/yahoo/bard/webservice/web/endpoints/JobsServletReactiveChainforResultsEndpointSpec.groovy
@@ -96,6 +96,7 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
         setup:
         TestSubscriber testSubscriber = new TestSubscriber<>()
         JobsApiRequest apiRequest = new JobsApiRequest(
+                null,
                 null,
                 null,
                 "",
@@ -121,6 +122,7 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
         setup:
         TestSubscriber testSubscriber = new TestSubscriber<>()
         JobsApiRequest apiRequest = new JobsApiRequest(
+                null,
                 null,
                 null,
                 "",
@@ -145,6 +147,7 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
         setup:
         TestSubscriber testSubscriber = new TestSubscriber<>()
         JobsApiRequest apiRequest = new JobsApiRequest(
+                null,
                 null,
                 null,
                 "",
@@ -174,7 +177,17 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
     def "getResults returns an empty observable if the PreResponse is not available in the PreResponseStore before the async timeout"() {
         setup:
         TestSubscriber testSubscriber = new TestSubscriber<>()
-        JobsApiRequest apiRequest = new JobsApiRequest(null, "5", "", "", null, uriInfo, jobPayloadBuilder, apiJobStore)
+        JobsApiRequest apiRequest = new JobsApiRequest(
+                null,
+                null,
+                "5",
+                "",
+                "",
+                null,
+                uriInfo,
+                jobPayloadBuilder,
+                apiJobStore
+        )
 
         when: "we start the async chain"
         jobsServlet.getResults("ticket3", apiRequest.asyncAfter).subscribe(testSubscriber)
@@ -190,6 +203,7 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
     def "If the PreResponse is available in the PreResponseStore and we miss the notification from broadcastChannel, we go to the PreResponseStore exactly once"() {
         setup:
         JobsApiRequest apiRequest1 = new JobsApiRequest(
+                null,
                 null,
                 "5",
                 "",
@@ -219,6 +233,7 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
 
         and:
         JobsApiRequest apiRequest = new JobsApiRequest(
+                null,
                 null,
                 "never",
                 "",
@@ -257,6 +272,7 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
     def "If the notification from broadcastChannel is not received within async timeout, we go to the PreResponseStore exactly once"() {
         setup:
         JobsApiRequest apiRequest1 = new JobsApiRequest(
+                null,
                 null,
                 "2",
                 "",
@@ -282,6 +298,7 @@ class JobsServletReactiveChainforResultsEndpointSpec extends Specification {
     def "If the notification from broadcastChannel is received within the async timeout, we go to the PreResponsestore twice"() {
         setup:
         JobsApiRequest apiRequest1 = new JobsApiRequest(
+                null,
                 null,
                 "never",
                 "",