views:

855

answers:

7

PHP makes this sort of thing dirt simple but I'd like to know how other languages do it. To standardize on a simple example, how would you implement the following webservice to sum a list of numbers:

http://server.com/sum?summands=LIST

where LIST is a list of space-separated real numbers. For example,

http://server.com/sum?summands=1+2+3

(note that spaces can be URL-encoded as pluses) should return

<sum>6</sum>

One language per answer!

ADDED: I mean this to be more than a fluffy survey question, ie, I hope it will be useful for people who want to dive in and create their first simple webservice/API. Pointers to good tutorials on getting started with webservices/APIs are also welcome.

This is a Rosetta Stone Question, showing how a certain simple task is accomplished in various languages/frameworks.

+3  A: 

PHP:

<?php

header("Content-Type: text/xml");
echo "<sum>", array_sum(split(' ', $_GET['summands'])), "</sum>";

?>
dreeves
+4  A: 

ASP.NET MVC

Global.asax:

void Application_OnStart(object sender, EventArgs e)
{
    RouteTable.Routes.MapRoute(
        "sum", 
        "sum",
        new { controller = "math", action = "sum" });
}

Controllers/MathController.cs:

public class MathController : Controller
{
    public ActionResult Sum(string summands)
    {
        var sum = summands.Split(' ').Sum(double.Parse);
        var xml = new XElement("sum", sum).ToString();
        return Content(xml, "application/xml");
    }
}
Greg Beech
+2  A: 

Perl:

#!/usr/bin/env perl

use CGI;

$query = new CGI;
$x = $query->param('summands');
$sum += $_ foreach split(' ', $x);
print "Content-type: text/xml\n\n";
print "<sum>$sum</sum>\n";

Note that for typical apache configurations you'll need to give the above a .cgi extension and make it world-executable. You can then use a mod_rewrite rule to not have to use the .cgi extension when actually calling the webservice. See this question: http://stackoverflow.com/questions/183921/rewrite-all-queries-to-not-need

(I'd be interested in seeing other ways to do this in Perl. The CGI module may be a bit old-school.)

dreeves
+2  A: 

Python, using WSGI and webob

from webob import Request, Response

def application(env, start_response):
    req = Request(env) 

    result = sum(float(n) for n in req.GET['summands'].split())
    res = Response(body="<sum>%g</sum>" % result,
                   content_type = "application/xml")

    return res(env, start_response)
dF
Thanks! Is this the canonical way to do it in Python?
dreeves
@dreeves: There are too many Python web-frameworks to talk about *canonical* way but the above code is as good as many.
J.F. Sebastian
+3  A: 

Ruby and Sinatra (not tested, but I believe it's close enough):

require 'sinatra'

get '/sum/:params' do |p|
    "<sum>#{p.split.inject{|acc,x| acc+x.to_i}}</sum>"
end
Paul Betts
Nice. For fair comparison can you include the full output with "Content-Type: text/xml" and all that? If that is somehow automatic, how would you override it to do text/plain or something?
dreeves
@Paul Betts: 1. `x` may be a float. 2. You've change interface (it might be for the better but OP's one is different).
J.F. Sebastian
@dreeves: Just follow the link. Its essential part is 9 lines long.
J.F. Sebastian
+3  A: 

In SWI-Prolog, using its HTTP package (i.e. built-in webserver). The code below doesn't just sum numbers but evaluates any arithmetical expression.

% Given that this file is called summands.pl,
% start the server by:
%
% swipl -g "[summands], start(8000)."
%
% Usage:
%
% http://localhost:8000/sum?summands=1.5*2/(3-4)
% returns <sum>-3.0</sum>
%
% http://localhost:8000/sum?summands=blah
% returns <error>ERROR</error>

:- use_module(library('http/thread_httpd')).
:- use_module(library('http/http_dispatch')).
:- use_module(library('http/http_parameters')).

:- http_handler('/sum', summands_handler, []).

start(Port) :-
    http_server(http_dispatch, [port(Port), workers(1)]),
    thread_get_message(_),
    halt.

summands_handler(Request) :-
    http_parameters(Request, [summands(Summands, [])]),
    catch(
        (
            evaluate(Summands, Result),
            with_output_to(atom(Output), format("<sum>~w</sum>", [Result]))
        ),
        _,
        Output = '<error>ERROR</error>'
    ),
    format('Content-type: text/xml\r\n\r\n~w', [Output]).

evaluate(Summands, Result) :-
    atom_to_term(Summands, SummandsAsTerm, _),
    Result is SummandsAsTerm.

To just sum numbers, redefine evaluate/2 as

evaluate(Summands, Result) :-
    concat_atom(Atoms, ' ', Summands),
    maplist(atom_number, Atoms, Numbers),
    sumlist(Numbers, Result).
Kaarel
Wow, this is great! I see this is its own web server as well -- the other answers rely on apache (or whatever).
dreeves
+6  A: 

Brainf*ck

The Apache module mod_bf (see also the source here) lets you use Brainf*ck programs in a CGI fashion. If you call the following program like http://www.example.com/test.bf?sum=1+2+3, it will add your numbers.

,,,,[-]>>>>>>+<<+[<<+>>,[----------[----------------------[-
----------[----[>>>]<<<[[->>>+<<<]<<<]>->>]]<<<+>>>]]<<[->>>
>>[>>>]<<<[-<[-<+>>>+<<]>>+<<<[>>>-<<<[-]]>>>[-<<+>>]<<<<]>>
[>>>]+[<<<]>>>[>[-<+>]<[->+>+<<]++++++++++[->[-<<<+>+>>]<<<[
>-[->>+<<]<[-]]>>]>[>>+<[-]<[->+<]]>[-<<+>>]>]<<<-[->+<]>[<+
>[-<+>]]<<<<[<<<]<]<[->>>+<<<]>>>]>>[>[-]>>]>>>>++++++++[-<+
+++++++>]<+++.>++++[-<+++++++++++>]<.-.++++++.>+++[-<----->]
<.>+++[-<+++>]<.++++++.>>+ A Rex ++++[-<+++++++++>]<.-------
------[-<->]<.>++++++[-<++++++>]<+.>+++[-<--->]<.>+++[-<----
>]<+.>++++++[-<------->]<-.>+++++[-<----->]<-.>+++++++[-<+++
+++++++++>]<.>+++[-<----->]<.>+++[-<++++++>]<+.----.>+++++++
[-<---------->]<+.>++++++++[-<+++++++++>]<+.>+++[-<---->]<+.
-.>>++[-<+++++>]<..[-]<+[-<+<+>>]>++++++[-<++++++++++>]<.<++
++++.++.<.>>++.<<<<<<[>++++++[-<++++++++>]<-.<<<]>>>[>>>]>>>
--.>>+++++++[-<+++++++>]<--.<<--.++.<.>>++.>>>++[-<+++++>]<.

Known issues:

  • You can only add non-negative integers.
  • Input is not validated in any way.
  • The standard mod_bf implementation won't let this add more than 30-digit numbers or so. It's a shame, because the program can actually add arbitrarily large integers (and as such, Muller's classic implementation lets you add multi-thousand-digit numbers). You can fix this issue by changing ARR_SIZE in mod_bf.
  • More than half of the source is just outputting Content-Type: text/xml. This, too, is really a shame because it makes brainf*ck look unnecessarily verbose. =P (Compare this program, which is slightly shorter but manages to compute arbitrarily large factorials.)
A. Rex
simply beautiful
Andreas Petersson