📄 OpenStreetMapSearchProvider.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading;
using MSearch.Domain;

namespace MSearch.SearchProviders.OpenStreetMap;

internal sealed class OpenStreetMapSearchProvider(HttpClient httpClient) : ISearchProvider
{
    public IAsyncEnumerable<SearchResult> Search(SearchQuery query, CancellationToken cancellationToken) =>
        httpClient
            .GetFromJsonAsAsyncEnumerable(
                $"https://nominatim.openstreetmap.org/search?format=json&q={Uri.EscapeDataString(query.Term)}",
                OpenStreetMapJsonSerializerContext.Default.OpenStreetMapItem,
                cancellationToken
            )
            .Where(item => item is not null)
            .Select(Map!);

    private static SearchResult Map(OpenStreetMapItem item) =>
        new(item.Name, item.DisplayName, new($"https://www.openstreetmap.org/{item.OmsType}/{item.OmsId}"));
}