public async Task LimitsPageSizeIsNotSet() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); // maximum page size is not set and client page size is 1 and it works var result = await client.GetFullJsonResponseAsync("api/companies/?page[size]=1"); var resultCount = ((JArray)result.Content["data"])?.Count; Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(1, resultCount); // maximum page size is not set and client page size is 1000 and it works and returns 100 records result = await client.GetFullJsonResponseAsync("api/companies/?page[size]=1000"); resultCount = ((JArray)result.Content["data"])?.Count; Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(100, resultCount); // client page size isn't specified and it works and returns 12 records // as default paging for this endpoint is 12 result = await client.GetFullJsonResponseAsync("api/companies/"); resultCount = ((JArray)result.Content["data"])?.Count; Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(12, resultCount); } }
public async Task PagedResultOnePageResult(string baseUrl, int firstPageNumber) { int itemsCount = 10; using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); // endpoint will return just 10 items that should be less than the whole page List <string> endpoints = new List <string>() { baseUrl, // lets ask for different page to be sure that it still will have correct first and last $"{baseUrl}?page[number]=1", // then ask for custom pageSize $"{baseUrl}?page[number]=1&page[size]=15", // then for custom pageSize but without pageNumber $"{baseUrl}?page[size]=15" }; foreach (var endpoint in endpoints) { var result = await client.GetFullJsonResponseAsync($"{baseUrl}"); var resultCount = ((JArray)result.Content["data"])?.Count; var last = result.Content["links"]["last"].Value <string>(); var first = result.Content["links"]["first"].Value <string>(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(itemsCount, resultCount); Assert.EndsWith($"{baseUrl}?page[number]={firstPageNumber}", first); Assert.EndsWith($"{baseUrl}?page[number]={firstPageNumber}", last); Assert.Null(result.Content["links"]["next"]); } } }
public async Task LimitsPageSize1() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); // maximum page size equal to client page size and it works var result = await client.GetFullJsonResponseAsync("api/companies/querypagesizelimit1/?page[size]=1"); var resultCount = ((JArray)result.Content["data"])?.Count; Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(1, resultCount); // maximum page size is lower than client page size and it fails result = await client.GetFullJsonResponseAsync("api/companies/querypagesizelimit1/?page[size]=10"); resultCount = ((JArray)result.Content["data"])?.Count; Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); Assert.Null(resultCount); // client page size isn't specified and it works and returns one record result = await client.GetFullJsonResponseAsync("api/companies/querypagesizelimit1/"); resultCount = ((JArray)result.Content["data"])?.Count; Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(1, resultCount); } }
public async Task RequiresApiResourceProviderInstance() { var config = new JsonApiConfiguration() { ApiResourceProviderFactory = new NullApiResourceProviderFactory() }; using (var server = new NewSetupJsonApiServer(config)) { var client = server.GetClient(); // id 1 is mapped to circle object var result = await client.GetJsonResponseAsync("api/shape/1"); _output.WriteLine(result.ToString()); var errors = result["errors"]; Assert.Equal(1, errors.Count()); var error = errors[0]; Assert.Equal("https://github.com/joukevandermaas/saule/wiki", error["links"]["about"].Value <string>()); Assert.Equal("Saule.JsonApiException", error["code"].Value <string>()); Assert.Equal("Saule.JsonApiException: ApiResourceProviderFactory returned null but it should always return an instance of IApiResourceProvider.", error["detail"].Value <string>()); } }
public async Task BuilderAndConverterConstructor() { var config = new JsonApiConfiguration { UrlPathBuilder = new CanonicalUrlPathBuilder(), JsonConverters = { new StringEnumConverter() } }; using (var server = new NewSetupJsonApiServer(config)) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/companies/456/"); _output.WriteLine(result.ToString()); Assert.Equal("National", result["data"]["attributes"]["location"].Value <string>()); result = await client.GetJsonResponseAsync("api/people/"); _output.WriteLine(result.ToString()); var relatedUrl = result["data"][0]["relationships"]["job"]["links"]["related"] .Value <string>(); Assert.Equal("http://localhost/corporations/456/", relatedUrl); } }
public async Task PassesThrough400Errors() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var response = await client.GetAsync("does/not/exist"); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } }
public async Task WorksForNoContent() { using (var server = new NewSetupJsonApiServer()) { var client = server.GetClient(); var result = await client.DeleteAsync("/api/companies/123"); Assert.Equal(HttpStatusCode.NoContent, result.StatusCode); } }
public async Task JsonApiAttributeRespondsWithJsonApi() { using (var server = new NewSetupJsonApiServer()) { var client = server.GetClient(addDefaultHeaders: false); var result = await client.GetJsonResponseAsync("api/people/123/usingJsonApiAttributeFilter"); Assert.NotEmpty(result["data"]["attributes"].Children()); } }
public async Task AppliesPaginationPageSizeFromAttribute() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/companies/"); _output.WriteLine(result.ToString()); Assert.Equal(12, (result["data"] as JArray)?.Count); } }
public async Task AppliesPaginationPageSizeFromClient() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/companies/querypagesizelimit50/?page[size]=5"); _output.WriteLine(result.ToString()); var resultCount = ((JArray)result["data"])?.Count; Assert.Equal(5, resultCount); } }
public async Task PassesThroughOneHttpException() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var response = await client.GetFullJsonResponseAsync("api/broken/exception"); var errors = response.Content["errors"]; Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); Assert.Equal(1, errors.Count()); Assert.Equal("An error has occurred.", errors[0]["title"]); } }
public async Task CamelCaseConstructor() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration { PropertyNameConverter = new CamelCasePropertyNameConverter() })) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/people/123"); Assert.Null(result["data"]["attributes"]["FirstName"]); Assert.NotNull(result["data"]["attributes"]["firstName"]); } }
public async Task PassesThroughHttpErrors() { using (var server = new NewSetupJsonApiServer()) { var client = server.GetClient(); var response = await client.GetFullJsonResponseAsync("api/broken"); _output.WriteLine(response.Content.ToString()); var errorText = response.Content["errors"][0]["title"].Value <string>(); Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); Assert.Equal("Authorization has been denied for this request.", errorText); } }
public async Task PassesThroughHttpError() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var response = await client.GetFullJsonResponseAsync("api/broken/error"); var errors = response.Content["errors"]; Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); Assert.Equal(1, errors.Count()); Assert.Equal("Error 1.", errors[0]["title"]); Assert.Equal("Type 1", errors[0]["code"]); } }
public async Task DenyOtherAttributesForHandlesQuery(string query, string expectedTitle) { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var response = await client.GetFullJsonResponseAsync(query); var error = response.Content["errors"][0]; Assert.Equal("Saule.JsonApiException", error["code"].Value <string>()); Assert.Equal(expectedTitle, error["title"].Value <string>()); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); } }
public async Task CamelCaseMeta() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration { PropertyNameConverter = new CamelCasePropertyNameConverter() })) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/people/123"); var meta = result["meta"]; Assert.NotNull(meta["numberOfFriends"]); Assert.NotNull(meta["numberOfFamilyMembers"]); } }
public async Task ConverterConstructor() { var config = new JsonApiConfiguration { JsonConverters = { new StringEnumConverter() } }; using (var server = new NewSetupJsonApiServer(config)) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/companies/456/"); _output.WriteLine(result.ToString()); Assert.Equal("National", result["data"]["attributes"]["location"].Value <string>()); } }
public async Task AppliesSortingConditionally() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/people?sort=age"); _output.WriteLine(result.ToString()); var ages = ((JArray)result["data"]) .Select(p => p["attributes"]["age"].Value <int>()) .ToList(); var sorted = ages.OrderBy(a => a).ToList(); Assert.NotEqual(sorted, ages); } }
public async Task CamelCaseNestedAttrs() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration { PropertyNameConverter = new CamelCasePropertyNameConverter() })) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/people/123"); var address = result["data"]["attributes"]["address"]; Assert.NotNull(address["streetName"]); Assert.NotNull(address["zipCode"]); } }
public async Task AppliesFiltering() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/query/people?filter[last-name]=Russel"); _output.WriteLine(result.ToString()); var names = ((JArray)result["data"]) .Select(p => p["attributes"]["last-name"].Value <string>()) .ToList(); var filtered = names.Where(a => a == "Russel").ToList(); Assert.Equal(filtered.Count, names.Count); } }
public async Task LimitsPageSize() { var apiConfig = new JsonApiConfiguration { PaginationConfig = new PaginationConfig { DefaultPageSize = 2, DefaultPageSizeLimit = 4 } }; using (var server = new NewSetupJsonApiServer(apiConfig)) { var client = server.GetClient(); var result = await client.GetFullJsonResponseAsync("api/companies/querypagesize/?page[size]=5"); Assert.Equal(HttpStatusCode.BadRequest, result.StatusCode); var resultCount = ((JArray)result.Content["data"])?.Count; Assert.Equal(null, resultCount); } }
public async Task DefaultConstructor() { using (var server = new NewSetupJsonApiServer()) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/companies/456/"); _output.WriteLine(result.ToString()); Assert.Equal(1, result["data"]["attributes"]["location"].Value <int>()); result = await client.GetJsonResponseAsync("api/people/"); _output.WriteLine(result.ToString()); var relatedUrl = result["data"][0]["relationships"]["job"]["links"]["related"] .Value <string>(); Assert.Equal("http://localhost/api/people/0/employer/", relatedUrl); } }
public async Task CamelCaseRelationships() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration { PropertyNameConverter = new CamelCasePropertyNameConverter() })) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync("api/people/123"); var relationships = result["data"]["relationships"]; Assert.NotNull(relationships["secretFriends"]); Assert.NotNull(relationships["familyMembers"]); Assert.Null(relationships["secret-friends"]); Assert.Null(relationships["family-members"]); } }
public async Task AppliesManualIncluding(string query, string[] expectedIncludes) { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var result = await client.GetJsonResponseAsync(query); // get all types that were included var includedTypes = ((JArray)result["included"]) ?.Select(p => p["type"].Value <string>()) .Distinct() .ToList() ?? new List <string>(); Assert.Equal(includedTypes.Count, expectedIncludes.Length); foreach (var expectedInclude in expectedIncludes) { Assert.Contains(expectedInclude, includedTypes); } } }
public async Task AppliesManualFiltering(string query, int?minAge, bool?hideLastName, int expectedSize) { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); if (minAge.HasValue) { query += $"{(query.Contains("?") ? "&" : "?")}filter[min-age]={minAge}"; } if (hideLastName.HasValue) { query += $"{(query.Contains("?") ? "&" : "?")}filter[hide-last-name]={hideLastName.Value}"; } var result = await client.GetJsonResponseAsync(query); var data = (JArray)result["data"]; var allLastNamesMissing = data.All( p => string.IsNullOrWhiteSpace(p["attributes"]["last-name"].Value <string>())); // calculate count of returned records that satisfy condition var validCount = data.Count(p => !minAge.HasValue || p["attributes"]["age"].Value <int>() >= minAge.Value); var totalCount = ((JArray)result["data"]).Count; Assert.Equal(expectedSize, validCount); Assert.Equal(totalCount, validCount); if (hideLastName.HasValue) { Assert.Equal(hideLastName.Value, allLastNamesMissing); } } }
public async Task DeserializeWorks() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration { PropertyNameConverter = new CamelCasePropertyNameConverter() })) { var client = server.GetClient(); var getResult = await client.GetJsonResponseAsync("api/people/123"); getResult.Remove("included"); var content = new StringContent(getResult.ToString()); content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.api+json"); var postResultMessage = await client.PostAsync("api/people/123", content); var postResult = JObject.Parse(await postResultMessage.Content.ReadAsStringAsync()); postResult.Remove("included"); Assert.True(JToken.DeepEquals(getResult, postResult)); } }
public async Task GivesUsefulError() { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var response = await client.GetFullJsonResponseAsync("api/broken/123/"); _output.WriteLine(response.ToString()); var result = response.Content; var error = result["errors"][0]; Assert.Equal("https://github.com/joukevandermaas/saule/wiki", error["links"]["about"].Value <string>()); Assert.Equal("Saule.JsonApiException", error["code"].Value <string>()); Assert.Equal("Saule.JsonApiException: You must add a [ReturnsResourceAttribute] to action methods.", error["detail"].Value <string>()); Assert.Equal(HttpStatusCode.InternalServerError, response.StatusCode); } }
public async Task AppliesSortingBeforePagination(string path) { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); var result1 = await client.GetJsonResponseAsync($"api/{path}/people?sort=age"); var result2 = await client.GetJsonResponseAsync($"api/{path}/people?sort=age&page[number]=1"); _output.WriteLine(result1.ToString()); _output.WriteLine(result2.ToString()); var ages1 = ((JArray)result1["data"]) .Select(p => p["attributes"]["age"].Value <int>()) .ToList(); var ages2 = ((JArray)result2["data"]) .Select(p => p["attributes"]["age"].Value <int>()) .ToList(); var sorted = ages1.Concat(ages2).OrderBy(a => a).ToList(); Assert.Equal(sorted, ages1.Concat(ages2).ToList()); } }
public async Task PagedResult(object baseUrl, int firstPageNumber) { using (var server = new NewSetupJsonApiServer(new JsonApiConfiguration())) { var client = server.GetClient(); // endpoint will return totalCount 100 items so we can calculate page numbers based on it // validate 100 pages by 1 page size var result = await client.GetFullJsonResponseAsync($"{baseUrl}?page[size]=1"); var resultCount = ((JArray)result.Content["data"])?.Count; var last = result.Content["links"]["last"].Value <string>(); var first = result.Content["links"]["first"].Value <string>(); var next = result.Content["links"]["next"].Value <string>(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(1, resultCount); Assert.EndsWith($"{baseUrl}?page[size]=1&page[number]={99 + firstPageNumber}", last); Assert.EndsWith($"{baseUrl}?page[size]=1&page[number]={firstPageNumber}", first); Assert.EndsWith($"{baseUrl}?page[size]=1&page[number]={firstPageNumber + 1}", next); // 12 pages by 9 page size result = await client.GetFullJsonResponseAsync($"{baseUrl}?page[size]=9"); resultCount = ((JArray)result.Content["data"])?.Count; last = result.Content["links"]["last"].Value <string>(); first = result.Content["links"]["first"].Value <string>(); next = result.Content["links"]["next"].Value <string>(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(9, resultCount); Assert.EndsWith($"{baseUrl}?page[size]=9&page[number]={11 + firstPageNumber}", last); Assert.EndsWith($"{baseUrl}?page[size]=9&page[number]={firstPageNumber}", first); Assert.EndsWith($"{baseUrl}?page[size]=9&page[number]={firstPageNumber + 1}", next); // 10 pages by 10 page size result = await client.GetFullJsonResponseAsync($"{baseUrl}?page[size]=10"); resultCount = ((JArray)result.Content["data"])?.Count; last = result.Content["links"]["last"].Value <string>(); first = result.Content["links"]["first"].Value <string>(); next = result.Content["links"]["next"].Value <string>(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(10, resultCount); Assert.EndsWith($"{baseUrl}?page[size]=10&page[number]={9 + firstPageNumber}", last); Assert.EndsWith($"{baseUrl}?page[size]=10&page[number]={firstPageNumber}", first); Assert.EndsWith($"{baseUrl}?page[size]=10&page[number]={firstPageNumber + 1}", next); // 5 pages by 20 default page size result = await client.GetFullJsonResponseAsync($"{baseUrl}"); resultCount = ((JArray)result.Content["data"])?.Count; last = result.Content["links"]["last"].Value <string>(); first = result.Content["links"]["first"].Value <string>(); next = result.Content["links"]["next"].Value <string>(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(20, resultCount); Assert.EndsWith($"{baseUrl}?page[number]={4 + firstPageNumber}", last); Assert.EndsWith($"{baseUrl}?page[number]={firstPageNumber}", first); Assert.EndsWith($"{baseUrl}?page[number]={firstPageNumber + 1}", next); // 3rd page with 20 default page size result = await client.GetFullJsonResponseAsync($"{baseUrl}?page[number]=2"); resultCount = ((JArray)result.Content["data"])?.Count; last = result.Content["links"]["last"].Value <string>(); first = result.Content["links"]["first"].Value <string>(); next = result.Content["links"]["next"].Value <string>(); Assert.Equal(HttpStatusCode.OK, result.StatusCode); Assert.Equal(20, resultCount); Assert.EndsWith($"{baseUrl}?page[number]={4 + firstPageNumber}", last); Assert.EndsWith($"{baseUrl}?page[number]={firstPageNumber}", first); Assert.EndsWith($"{baseUrl}?page[number]=3", next); } }