Skip to content

Commit 6f1c8c4

Browse files
committed
Fixing error 414 when too many objects are requested.
Adding GetElements(OsmGeoKey[]) which can request different types in one call.
1 parent 3fa1dc1 commit 6f1c8c4

File tree

4 files changed

+54
-9
lines changed

4 files changed

+54
-9
lines changed

FunctionalTests/Tests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Threading.Tasks;
66
using OsmSharp.API;
77
using OsmSharp.Changesets;
8+
using OsmSharp.Db;
89
using OsmSharp.Tags;
910

1011
namespace OsmSharp.IO.API.FunctionalTests
@@ -70,7 +71,9 @@ public static async Task TestClient(INonAuthClient client)
7071
var multifetchNodes = await client.GetNodes(new Dictionary<long, long?>() { { nodeId, null }, { nodeId + 1, 1 } });
7172
var nodeRelations = await client.GetNodeRelations(nodeId);
7273
var nodeWays = await client.GetNodeWays(nodeId);
73-
True(nodeHistory?.Any(), multifetchNodes?.Any(), nodeRelations?.Any(), nodeWays?.Any());
74+
var multifetchElements = await client.GetElements(
75+
map.Nodes.Select(n => new OsmGeoKey(n)).Concat(map.Ways.Select(n => new OsmGeoKey(n))).ToArray());
76+
True(nodeHistory?.Any(), multifetchNodes?.Any(), nodeRelations?.Any(), nodeWays?.Any(), multifetchElements?.Any());
7477
var changeset = await client.GetChangeset(node.ChangeSetId.Value);
7578
var changesetWithDiscussion = await client.GetChangeset(node.ChangeSetId.Value, true);
7679
NotNull(changeset, changesetWithDiscussion?.Discussion);

src/INonAuthClient.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using OsmSharp.API;
66
using OsmSharp.Changesets;
77
using OsmSharp.Complete;
8+
using OsmSharp.Db;
89

910
namespace OsmSharp.IO.API
1011
{
@@ -29,6 +30,8 @@ public interface INonAuthClient
2930
Task<Node[]> GetNodes(params long[] ids);
3031
Task<Way[]> GetWays(params long[] ids);
3132
Task<Relation[]> GetRelations(params long[] ids);
33+
Task<OsmGeo[]> GetElements(params OsmGeoKey[] elementKeys);
34+
Task<OsmGeo[]> GetElements(Dictionary<OsmGeoKey, long?> elementKeyVersions);
3235
Task<Node[]> GetNodes(IEnumerable<KeyValuePair<long, long?>> idVersions);
3336
Task<Way[]> GetWays(IEnumerable<KeyValuePair<long, long?>> idVersions);
3437
Task<Relation[]> GetRelations(IEnumerable<KeyValuePair<long, long?>> idVersions);

src/NonAuthClient.cs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
using System.IO;
1414
using System.Web;
1515
using Microsoft.Extensions.Logging;
16+
using OsmSharp.Db;
1617

1718
namespace OsmSharp.IO.API
1819
{
@@ -342,19 +343,57 @@ public async Task<Relation[]> GetRelations(IEnumerable<KeyValuePair<long, long?>
342343
return await GetElements<Relation>(idVersions);
343344
}
344345

346+
public async Task<OsmGeo[]> GetElements(params OsmGeoKey[] elementKeys)
347+
{
348+
return await GetElements(elementKeys.ToDictionary(ek => ek, ek => (long?)null));
349+
}
350+
351+
public async Task<OsmGeo[]> GetElements(Dictionary<OsmGeoKey, long?> elementKeyVersions)
352+
{
353+
var elements = new List<OsmGeo>();
354+
355+
foreach (var typeGroup in elementKeyVersions.GroupBy(kvp => kvp.Key.Type))
356+
{
357+
var chunkAsDictionary = typeGroup.ToDictionary(kvp => kvp.Key.Id, kvp => kvp.Value);
358+
if(typeGroup.Key == OsmGeoType.Node)
359+
elements.AddRange(await GetElements<Node>(chunkAsDictionary));
360+
else if (typeGroup.Key == OsmGeoType.Way)
361+
elements.AddRange(await GetElements<Way>(chunkAsDictionary));
362+
else if (typeGroup.Key == OsmGeoType.Relation)
363+
elements.AddRange(await GetElements<Relation>(chunkAsDictionary));
364+
}
365+
366+
return elements.ToArray();
367+
}
368+
345369
/// <summary>
346370
/// Elements Multifetch
347371
/// <see href="https://wiki.openstreetmap.org/wiki/API_v0.6#Multi_fetch:_GET_.2Fapi.2F0.6.2F.5Bnodes.7Cways.7Crelations.5D.3F.23parameters">
348372
/// GET /api/0.6/[nodes|ways|relations]?#parameters</see>.
349373
/// </summary>
350374
private async Task<TOsmGeo[]> GetElements<TOsmGeo>(IEnumerable<KeyValuePair<long, long?>> idVersions) where TOsmGeo : OsmGeo, new()
351375
{
352-
var type = new TOsmGeo().Type.ToString().ToLower();
353-
// For exmple: "12,13,14v1,15v1"
354-
var parameters = string.Join(",", idVersions.Select(e => e.Value.HasValue ? $"{e.Key}v{e.Value}" : e.Key.ToString()));
355-
var address = BaseAddress + $"0.6/{type}s?{type}s={parameters}";
356-
var elements = await GetOfType<TOsmGeo>(address);
357-
return elements.ToArray();
376+
var tasks = new List<Task<IEnumerable<TOsmGeo>>>();
377+
378+
foreach (var chunk in Chunks(idVersions, 400)) // to avoid http error code 414, UIR too long.
379+
{
380+
var type = new TOsmGeo().Type.ToString().ToLower();
381+
// For exmple: "12,13,14v1,15v1"
382+
var parameters = string.Join(",", idVersions.Select(e => e.Value.HasValue ? $"{e.Key}v{e.Value}" : e.Key.ToString()));
383+
var address = BaseAddress + $"0.6/{type}s?{type}s={parameters}";
384+
tasks.Add(GetOfType<TOsmGeo>(address));
385+
}
386+
387+
await Task.WhenAll(tasks);
388+
389+
return tasks.SelectMany(t => t.Result).ToArray();
390+
}
391+
392+
private IEnumerable<T[]> Chunks<T>(IEnumerable<T> elements, int chunkSize)
393+
{
394+
return elements.Select((e, i) => new { e, i })
395+
.GroupBy(ei => ei.i / chunkSize) // Intentional integer division
396+
.Select(g => g.Select(ei => ei.e).ToArray());
358397
}
359398

360399
/// <summary>

src/OsmApiClient.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
<PropertyGroup>
44
<TargetFramework>netstandard2.0</TargetFramework>
55
<PackageId>OsmApiClient</PackageId>
6-
<Version>0.0.1</Version>
6+
<Version>0.0.2</Version>
77
<RepositoryUrl>https://github.com/OsmSharp/osm-api-client/</RepositoryUrl>
8-
<PackageReleaseNotes>First Release</PackageReleaseNotes>
8+
<PackageReleaseNotes>Adding GetElements(OsmGeoKey[] keys) which can fetch multiple element types in one call.</PackageReleaseNotes>
99
<PackageProjectUrl>https://github.com/OsmSharp/osm-api-client/</PackageProjectUrl>
1010
<Description>This is a simple C# client to allow using OSM API easily.</Description>
1111
<PackageTags>osm;openstreetmap;client</PackageTags>

0 commit comments

Comments
 (0)