Skip to main content
28 of 43
deleted 229 characters in body
Sky Sanders
  • 12.1k
  • 3
  • 32
  • 60

Soapi.CS : A rich fluent .NET Stack Overflow API client library - complete. finally.

##Soapi.CS for .Net / Silverlight / Windows Phone 7 / Mono Quick and Easy:

var questionWithStuff =sofu
    .Questions
    .Tagged("asp.net","c#")
    .FromDate("january 1, 2001")
    .ToDate(new DateTime(2020, 10, 10))
    .WithBody
    .WithAnswers
    .WithComments
    .Page(1)
    .PageSize(2)
    .Pages(3)
    .Sort(QuestionSort.Votes)
    .Min(1)
    .Max(100)
    .Order(SortOrder.Asc)
    .ToList();

Assert.AreEqual(6, questionWithStuff.Count);

// issues the following requests

// http://api.stackoverflow.com/1.0/questions?answers=true&body=true&comments=true&fromdate=978307200&max=100&min=1&order=Asc&page=1&pagesize=2&sort=Votes&tagged=asp.net%3bc%23&todate=1602288000
// http://api.stackoverflow.com/1.0/questions?answers=true&body=true&comments=true&fromdate=978307200&max=100&min=1&order=Asc&page=2&pagesize=2&sort=Votes&tagged=asp.net%3bc%23&todate=1602288000
// http://api.stackoverflow.com/1.0/questions?answers=true&body=true&comments=true&fromdate=978307200&max=100&min=1&order=Asc&page=3&pagesize=2&sort=Votes&tagged=asp.net%3bc%23&todate=1602288000

For those who want more:

var sofu = ctx.Official.StackOverflow;

var interestingQuestions =
    from question in sofu.Questions.Unanswered.WithAnswers
    where question.AnswerCount > 0
    orderby question.CreationDate descending
    select new
    {
        Asker = question.Owner.DisplayName,
        Title = question.Title,
        Answers = question.Answers,
        AskerFavCount = question.Owner.Favorites.Total,
        AskerFaves = question.Owner.Favorites
    };


foreach (var item in interestingQuestions)
{

    Console.WriteLine("----------------------------------------\r\n");
    Console.WriteLine("{0} asked '{1}'",item.Asker, item.Title);

    if (item.AskerFavCount>0)
    {
        Console.WriteLine("\t asker likes:");

        foreach (Question fave in item.AskerFaves)
        {
            Console.WriteLine("\t\t{0}", fave.Title);
        }
    }

    Console.WriteLine();

    foreach (var answer in item.Answers)
    {
        // here we are lazy loading the answer's owner and 
        // then eager loading his other answers

        var answerOwnerTopAnswer =
            answer.Owner.Answers
            .Sort(PostSort.Votes)
            .PageSize(1)
            .FirstOrDefault();

        int answerOwnerTopScore = answerOwnerTopAnswer != null
            ? answerOwnerTopAnswer.Score
            : 0;

        Console.WriteLine("Answerer {0}, credibility {1}",
            answer.Owner.DisplayName, answerOwnerTopScore);
    }

    Console.WriteLine();
}

Output:


----------------------------------------

nash asked 'are big programming languages implemented using tools like antlr ,javacc etc'

Answerer duffymo, credibility 33

----------------------------------------

Mr Bell asked 'Why can't I bind ItemsControl's ItemsSource and define a data template at the same time? WPF'

Answerer Reed Copsey, credibility 46

----------------------------------------

MikeN asked 'Django template tag to return IP Address?'
     asker likes:
        Django template tag to return IP Address?
        Move to 2 Django physical servers (front and backend) from a single production server? 
        How do you clear your mind after a day of coding?
        Django Rename and change data type of model field live with zero downtime?
        Best way to define private methods for a class in Objective-C
        FOSS Intelligent Character Recognition (ICR)
        Show different contact info on a website based on IP Address US State geolocation?
        What is the best comment in source code you have ever encountered?
        How can I obfuscate JavaScript?
        How do you beta test an iphone app?
        HOWTO: Write Python API wrapper?
        Having Django serve downloadable files
        How to implement a reputation system like Stack Overflow?
        How to implement DomainKeys?
        WSDL validator
        Tool to view response headers
        Programattically populate sample data for Django Image/File fields?
        How does the mail icon count number show up on the iPad / iPhone
        Does a "blog" sub-domain help the pagerank of your main site?
        can't start MySql in Mac OS 10.6 Snow Leopard 
        What is the best rich textarea editor for jQuery?
        Find the field names of inputtable form fields in a PDF document?
         Add BarButtonItem to Navigation Controller in Popover
        How to check if a string in Python is in ASCII?
        iPhone - Debugging EXC_BAD_ACCESS crashes
        Programmatically get own phone number in iPhone OS
        In a django web application, how do you give users their own subdomain?
        Python module for converting PDF to text
        Objective C: Version of JSON library I'm compiling in present in another library I'm linking in via .a, how to resolve conflict?
        Subdomain not included in the "?next=" for Django auth login?

Answerer S.Lott, credibility 417

----------------------------------------

Ken M asked 'Java HTTP Post Raw Data'

Answerer duffymo, credibility 33

----------------------------------------

Quincy asked 'Windows Service doesn't start automatically'
     asker likes:
        I'm graduating with a Computer Science degree but I don't feel like I know how to program.
        Difference between i++ and ++i in a loop?
        Is there a performance difference between i++ and ++i in C++?

Answerer John, credibility 0

----------------------------------------

oppoeee asked 'What technology are they using in this Shopkick demo to achieve pinpoint geoLocation?'

Answerer ohhorob, credibility 7

Requests Issued:


http://api.stackoverflow.com/1.0/questions/unanswered?answers=true&page=1
http://api.stackoverflow.com/1.0/users/410942/favorites?page=1&pagesize=0
http://api.stackoverflow.com/1.0/users/37213?page=1
http://api.stackoverflow.com/1.0/users/37213/answers?page=1&pagesize=1&sort=Votes
http://api.stackoverflow.com/1.0/users/122229/favorites?page=1&pagesize=0
http://api.stackoverflow.com/1.0/users/65358?page=1
http://api.stackoverflow.com/1.0/users/65358/answers?page=1&pagesize=1&sort=Votes
http://api.stackoverflow.com/1.0/users/36680/favorites?page=1&pagesize=0
http://api.stackoverflow.com/1.0/users/36680/favorites?page=1
http://api.stackoverflow.com/1.0/users/10661?page=1
http://api.stackoverflow.com/1.0/users/10661/answers?page=1&pagesize=1&sort=Votes
http://api.stackoverflow.com/1.0/users/411438/favorites?page=1&pagesize=0
http://api.stackoverflow.com/1.0/users/103369/favorites?page=1&pagesize=0
http://api.stackoverflow.com/1.0/users/103369/favorites?page=1
http://api.stackoverflow.com/1.0/users/411428?page=1
http://api.stackoverflow.com/1.0/users/411428/answers?page=1&pagesize=1&sort=Votes
http://api.stackoverflow.com/1.0/users/397743/favorites?page=1&pagesize=0
http://api.stackoverflow.com/1.0/users/178831?page=1
http://api.stackoverflow.com/1.0/users/178831/answers?page=1&pagesize=1&sort=Votes

##About

A robust, easy to use, strongly typed, end-to-end StackOverflow API Client Library.

Out of the box, Soapi provides you with a robust client library that abstracts away most all of the messy details of consuming the API and lets you concentrate on implementing your ideas.

A few features include:

  • Full coverage of the API, all routes and all parameters.

  • Strongly typed Domain Data Objects for all API data structures.

  • Eager and Lazy Loading objects. Currently the Soapi workflow involves creating a RouteMap the corresponds to a specific API route and fetching results.

    As an example, when you query for questions, there is a skeleton User object provided that contains just the most relevant fields. Suppose you would like to get the full User object for the owner of a question and then in turn get some of his other good answers....

      var aSmartGuy = thisQuestion.AcceptedAnswer.Owner;
      \\ other answers by aSmartGuy
      aSmartGuy.Answers(sort:PostSort.Votes)
       .ForEach(a=>Console.WriteLine(a.Title));
    

    Now think about how many API requests are required to accomplish this and how nice it will be to just get the data and not worry about building routes.

    Lazy loading may be disabled.

  • When finer grained control of requests is desired, the core RouteMap objects may be leveraged to request data from any of the API paths using all available parameters as documented on the help pages.

  • A rich Asynchronous implementation.

  • A configurable request cache to reduce unnecessary network traffic and to simplify your usage logic. There is no need to go out of your way to be frugal.

    The RequestCache caches all requests for a minimum of 60 seconds, by default. This value is adjustable. You may also set a distinct cache duration for any particular route.

    e.g. You typically need to get the list of sites from stackauth every few hours.

    RequestCache.SetDuration(typeof(SitesRouteMap), new TimeSpan(2,0,0));

  • A configurable request throttle to ensure compliance with the api terms of usage and to simplify your code in that you do not have to worry about and respond to 503 errors.

    By default, the throttle is set to maintain a minimum interval of 170ms (.17 seconds) between requests. If you would like to manage your requests manually simply set the throttle to 0.

    The RequestCache and Throttled Queue are thread-safe, so can make as many requests as you like from as many threads as you like as fast as you like and not worry about abusing the api or having to write reams of management/compensation code.

  • Configurable retry threshold that will, by default, make up to 3 attempts to retrieve a request before failing. Every request made by Soapi is properly formed and directed so most any http error will be the result of a timeout or other network infrastructure. A retry buffer provides a level of fault tolerance that you can rely on.

  • An almost identical javascript library, Soapi.JS, that will enable you to leverage your server cycles and bandwidth for only those tasks that require it and offload things like status updates to the client's browser.

##License

Licensed GPL Version 2 license.

##Platforms

  • .NET 3.5
  • .NET 4.0
  • Silverlight 3
  • Silverlight 4
  • Windows Phone 7
  • Mono

##Download

Source code lives @ http://soapics.codeplex.com. Binary releases are forthcoming.

codeplex is acting up again.

get the source @ http://bitbucket.org/bitpusher/soapi.cs

The source is C# 3.5. and includes projects and solutions for the following IDEs

  • Visual Studio 2008
  • Visual Studio 2010
  • ModoDevelop 2.4

##Documentation

Full documentation is available at http://soapi.info/help/cs/index.aspx

##Sample Code / Usage Examples Sample code and usage examples will be added as answers to this question.

The CS/SL/WP7/MONO libraries all compile the same code and with the exception of environmental considerations of Silverlight, the code samples are valid for all libraries.

You may also find guidance in the test suites.

##Contact

This library is currently the effort of me, Sky Sanders (code poet) and can be reached at gmail - sky.sanders

Any who are interested in improving this library are welcome.

Sky Sanders
  • 12.1k
  • 3
  • 32
  • 60