Skip to content

Commit

Permalink
GraphQL 4.0.0 Bump. Project clean up. (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoeHartzell authored Apr 15, 2021
1 parent 67faa91 commit eae38b7
Show file tree
Hide file tree
Showing 30 changed files with 486 additions and 3,379 deletions.
229 changes: 118 additions & 111 deletions src/GraphQL.Relay.StarWars/Api/Swapi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,139 +2,146 @@
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using DataLoader;
using GraphQL.Relay.StarWars.Utilities;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.IO;

namespace GraphQL.Relay.StarWars.Api
{
public class Swapi
{
private readonly HttpClient _client;

private string _apiBase = "http://swapi.co/api";
private ResponseCache _cache = new ResponseCache();


private string GetResource<T>() where T : Entity
public class Swapi
{
return typeof(T).Name.ToLower();
}
private readonly HttpClient _client;

public Swapi(ResponseCache cache)
{
_cache = cache;
_client = new HttpClient();
_client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json")
);
}
private string _apiBase = "http://swapi.dev/api";
private ResponseCache _cache = new ResponseCache();

public Task<T> Fetch<T>(Uri url) where T : ISwapiResponse
{
return _cache.GetOrAdd(url, async u =>
{
var result = await _client.GetAsync(u);
return DeserializeObject<T>(
await result.Content.ReadAsStringAsync()
);
}).ContinueWith(
t => (T)t.Result,
TaskContinuationOptions.OnlyOnRanToCompletion |
TaskContinuationOptions.ExecuteSynchronously
);
}

public async Task<IEnumerable<T>> FetchMany<T>(IEnumerable<Uri> urls)
where T : Entity
{
var entities = await Task.WhenAll(urls.Select(Fetch<T>));
return entities.AsEnumerable();
}

public async Task<T> GetEntity<T>(string id) where T : Entity
{
var name = GetResource<T>();
var entity = await GetEntity<T>(new Uri($"{_apiBase}/{name}/{id}"));

return entity;
}

public Task<T> GetEntity<T>(Uri url) where T : Entity =>
Fetch<T>(url);


public Task<IEnumerable<T>> GetMany<T>(IEnumerable<Uri> urls) where T : Entity =>
FetchMany<T>(urls);
private string GetResource<T>() where T : Entity
{
return typeof(T).Name.ToLower();
}

public Swapi(ResponseCache cache)
{
_cache = cache;
_client = new HttpClient(new HttpClientHandler
{
AllowAutoRedirect = true,
MaxAutomaticRedirections = 3
})
{
Timeout = TimeSpan.FromSeconds(30),
};

private bool DoneFetching(int count, ConnectionArguments args)
{
if (args.After != null || args.Before != null || args.Last != null || args.First == null)
return false;
return count >= args.First.Value;
}
public async Task<List<T>> GetConnection<T>(ConnectionArguments args)
where T : Entity
{
var nextUrl = new Uri($"{_apiBase}/{typeof(T).Name.ToLower()}");
var entities = new List<T>();
var canStopEarly =
args.After != null ||
args.Before != null ||
args.Last != null ||
args.First == null;

EntityList<T> page;
while (nextUrl != null && !DoneFetching(entities.Count, args))
{
page = await Fetch<EntityList<T>>(nextUrl);
entities.AddRange(page.Results);
nextUrl = page.Next;
}

return entities;
}
_client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json")
);
}

private T DeserializeObject<T>(string payload)
{
return JsonConvert.DeserializeObject<T>(
payload,
new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
public Task<T> Fetch<T>(Uri url) where T : ISwapiResponse
{
return _cache.GetOrAdd(url, async u =>
{
NamingStrategy = new SnakeCaseNamingStrategy()
},
Converters = new List<JsonConverter> {
var result = await _client.GetAsync(u);
return DeserializeObject<T>(await result.Content.ReadAsStringAsync());
}).ContinueWith(
t => (T)t.Result,
TaskContinuationOptions.OnlyOnRanToCompletion |
TaskContinuationOptions.ExecuteSynchronously
);
}

public async Task<IEnumerable<T>> FetchMany<T>(IEnumerable<Uri> urls)
where T : Entity
{
var entities = await Task.WhenAll(urls.Select(Fetch<T>));
return entities.AsEnumerable();
}

public async Task<T> GetEntity<T>(string id) where T : Entity
{
var name = GetResource<T>();
var entity = await GetEntity<T>(new Uri($"{_apiBase}/{name}/{id}"));

return entity;
}

public Task<T> GetEntity<T>(Uri url) where T : Entity =>
Fetch<T>(url);


public Task<IEnumerable<T>> GetMany<T>(IEnumerable<Uri> urls) where T : Entity =>
FetchMany<T>(urls);


private bool DoneFetching(int count, ConnectionArguments args)
{
if (args.After != null || args.Before != null || args.Last != null || args.First == null)
return false;
return count >= args.First.Value;
}
public async Task<List<T>> GetConnection<T>(ConnectionArguments args)
where T : Entity
{
var nextUrl = new Uri($"{_apiBase}/{typeof(T).Name.ToLower()}/");
var entities = new List<T>();
var canStopEarly =
args.After != null ||
args.Before != null ||
args.Last != null ||
args.First == null;

EntityList<T> page;
while (nextUrl != null && !DoneFetching(entities.Count, args))
{
page = await Fetch<EntityList<T>>(nextUrl);
entities.AddRange(page.Results);
nextUrl = page.Next;
}

return entities;
}

private T DeserializeObject<T>(string payload)
{
return JsonConvert.DeserializeObject<T>(
payload,
new JsonSerializerSettings
{
ContractResolver = new DefaultContractResolver
{
NamingStrategy = new SnakeCaseNamingStrategy()
},
Converters = new List<JsonConverter> {
new NumberConverter()
}
}
);
}
}
);
}
}
}

public class NumberConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
throw new NotImplementedException();

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
public class NumberConverter : JsonConverter
{
if (objectType == typeof(int))
return int.Parse(reader.Value.ToString());
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) =>
throw new NotImplementedException();

if (objectType == typeof(double))
return double.Parse(reader.Value.ToString());
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (objectType == typeof(int))
return int.Parse(reader.Value.ToString());

return reader.Value;
}
if (objectType == typeof(double))
return double.Parse(reader.Value.ToString());

return reader.Value;
}

public override bool CanConvert(Type objectType) =>
objectType == typeof(int) || objectType == typeof(double);
public override bool CanConvert(Type objectType) =>
objectType == typeof(int) || objectType == typeof(double);

}
}
}
52 changes: 0 additions & 52 deletions src/GraphQL.Relay.StarWars/Controllers/GraphQLController.cs

This file was deleted.

10 changes: 6 additions & 4 deletions src/GraphQL.Relay.StarWars/GraphQL.Relay.StarWars.csproj
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Folder Include="wwwroot\" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DataLoader" Version="0.2.0" />
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
<PackageReference Include="GraphQL" Version="2.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="10.0.3" />
<PackageReference Include="GraphQL" Version="4.0.2" />
<PackageReference Include="GraphQL.MicrosoftDI" Version="4.0.2" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore" Version="5.0.0" />
<PackageReference Include="GraphQL.Server.Transports.AspNetCore.SystemTextJson" Version="5.0.0" />
<PackageReference Include="GraphQL.SystemTextJson" Version="4.0.2" />
<PackageReference Include="Scrutor" Version="2.1.2" />
</ItemGroup>
<ItemGroup>
Expand Down
Loading

0 comments on commit eae38b7

Please sign in to comment.