NuGet Services (Search, Publishing, etc.)

Related Bugs

Problem Statement

Currently, NuGet uses OData queries for its internal search needs. This has benefits in that the client can create new types of ad-hoc searches without requiring changes to the server. The downside is that for simple searches, the URL looks like this:

http://packages.nuget.org/v1/FeedService.svc/Packages()?$filter=(((Id%20ne%20null)%20and%20substringof('foo',tolower(Id)))%20or%20((Description%20ne%20null)%20and%20substringof('foo',tolower(Description))))%20or%20((Tags%20ne%20null)%20and%20substringof('%20foo%20',tolower(Tags)))&$orderby=DownloadCount%20desc,Id&$skip=0&$top=30

That’s just for a search of the string “foo”. A lot of the post search filtering still happens on the client side.

Here's an example of checking for updates which requires multiple requests:

GET /v1/FeedService.svc/Packages()?$filter=(((((((((tolower(Id)%20eq%20'blogml')%20or%20(tolower(Id)%20eq%20'dotnetopenauth'))%20or%20(tolower(Id)%20eq%20'dotnetzip'))%20or%20(tolower(Id)%20eq%20'httpmodulemagic'))%20or%20(tolower(Id)%20eq%20'jayrock-json'))%20or%20(tolower(Id)%20eq%20'jayrock'))%20or%20(tolower(Id)%20eq%20'log4net'))%20or%20(tolower(Id)%20eq%20'lucene'))%20or%20(tolower(Id)%20eq%20'ninject'))%20or%20(tolower(Id)%20eq%20'ninject.mvc3')&$orderby=Id&$skip=0&$top=90 HTTP/1.1

Proposal

We should look into whether we can have specific methods on the server that still return the same objects that the OData endpoints do, such as an IQueryable<Package>.

Is it possible to add methods to an OData service?

There are two types of searches we’ve identified so far:

  • Package Search (As we do in the dialog)
  • Package Id Search for Intellisense (Just returns package IDs)

API

OData Service Methods

public IQueryable<IPackage> Search(string searchTerm, string targetFramework, bool latestVersionOnly); // Search
public IEnumerable<string> GetPackageIdsStartingWith(string searchTerm); // Intellisense
public IDictionary<string, object> GetCapabilities();
public IQueryable<IPackage> GetUpdates(string installedPackages);
IEnumerable<IPackage> GetPackagesByTags(string tags, bool latestVersionOnly);

Notes

  • NuGet 1.5: Only implement the Search method.
  • NuGet > 1.5: Implement the others.
  • GetStatistics is a loosely typed dictionary so we can add statistics without having to recompile the client.
  • We need service methods for scenarios where we may want to change the behavior on the server without changing the client.
    • GetPackageVersionsForId is not necessary because it is unlikely to ever change.
  • New clients attempting to call old servers will return a 404. Client should fallback to old behavior.
  • Old clients calling new server will simply use the old way.
  • OData Service methods don’t allow passing complex objects. We’ll need to use a a formatted string (Pipe delimited using colon to separate package id and versions as in “Iesi.Collections:3.1.0.4000|log4net:1.2.10|NHibernate:3.1.0.4000”) for the list of installed packages and list of tags.

Open Questions

  • Are there other parameters we need to the Search method.
    • For example, how would we filter out chocolatey packages from places where it doesn't make sense (aka ASP.NET Web Pages and Visual Studio)?
    • How do we filter out tools packages from ASP.NET Web Pages?
  • How do we represent the target project type and target framework? At some point we may want to filter packages based on those things.
  • On the other hand, perhaps we need a syntax that’s completely embodied in the search term. For example “Elmah projectType:ClassLib targetFX:Net40”
  • Any other considerations to think about?

For Later

public IEnumerable<string> GetPackageVersionsForId(string id); // Version intellisense. We can use OData
public PackageSourceStatistics GetStatistics(); 
public PackageStatistics GetStatistics(string packageId);
public string GetApiKey(string username, password); // Requires SSL

Last edited Jul 15, 2011 at 10:45 PM by Haacked, version 16