www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - D2 & Web-Framework

reply =?iso-8859-1?Q?Robert_M._M=FCnch?= <robert.muench robertmuench.de> writes:
Hi, is there a matured framework for building the server side part of 
web-apps in D2? I don't need totally fancy things, session handling, 
dynamic content and simple output generation.

-- 
Robert M. Münch
http://www.robertmuench.de
Jul 14 2011
next sibling parent reply Trass3r <un known.com> writes:
http://arsdnet.net/dcode/
Jul 14 2011
next sibling parent reply Adam Ruppe <destructionator gmail.com> writes:
 http://arsdnet.net/dcode/
In there, you'll find most my files for the websites I create in D. The basic one is cgi.d. It gives easy access to things like get and post variables, uploaded files, and writing out responses. I think it works standing alone, but it might require the sha.d in there too now (I've been a little sloppy on that stuff recently.) Example: === import arsd.cgi; void mySite(Cgi cgi) { if("name" in cgi.get) cgi.write("hello, world, "~cgi.get["name"]~"!"); else cgi.write("Hello! Add ?name=yourname to the url for a message."); } mixin GenericMain!mySite; ==== the genericmain creates a main() function that creates the cgi object for you and calls the given function. cgi.get and cgi.post are plain immutable string[string] for getting parameters. There's a lot of stuff in there, but just this can do a fair amount. Pretty straightforward stuff. Also in that folder are a bunch of helpers. database.d and mysql/postgres/sqlite for databases. dom.d provides a javascript style DOM. I use this for templating - create a Document object from an existing html file. Then, insert your data or otherwise manipulate it. Then, at the end, do a cgi.write(document.toString()); to finish it off. Of course, you don't have to do it that way. Finally, web.d builds on top of dom and cgi to provide a higher level interface; instead of manually parsing the cgi object, it tries to do it automatically, to call your functions with reflection. Example: ===== import arsd.web; class MySite : ApiProvider { string hello(string name) { return "Hello, " ~ name ~ "!"; } } mixin FancyMain!MySite; ===== (the base class is called ApiProvider right now because I found it was great for producing functions to be called from javascript - all automatically - but it was originally made for doing full sites.) What it does is takes a class and makes it's functions callable via urls. The arguments are used to build automatic forms, if needed, to ask the user for parameters and the return value is used to build a response in various data formats. The cgi object is a member of the ApiProvider base class, so you can always use it in a more traditional manner too, ignoring most the fancy wrapper and just writing void, argumentless functions. However, then you lose a lot of the good stuff! Anyway it's default output is a DOM document. You can override methods from the base class to provide your own document and post processor. I've been light on writing documentation for any of this, but cgi.d at least should be pretty straight forward for doing work with.
Jul 14 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Adam Ruppe" <destructionator gmail.com> wrote in message 
news:ivms0h$s8p$1 digitalmars.com...
 Finally, web.d builds on top of dom and cgi to provide a higher
 level interface; instead of manually parsing the cgi object, it tries
 to do it automatically, to call your functions with reflection.
I recently started giving your web.d a try, but I'm having trouble figuring out how to use the executable. I have this (a modification of your ApiDemo example): import arsd.cgi; import arsd.web; class ArticlesApi : ApiProvider { private static Document document; private /+static+/ void loadDocument() { if(!document) document = new Document(import("document.html"), true, true); } this() { loadDocument(); } override Document _defaultPage() { auto e = _getGenericContainer(); e.innerText = "Hello!"; return document; } override Element _getGenericContainer() { return document.getElementById("page-content"); } } mixin FancyMain!ArticlesApi; But, when I try to run it through IIS, it just does a 302 redirect to "localstart.asp". I totally forget how HTTP headers are passed to an exe for CGI, but FWIW, if I run it at the command-line, no matter what I give as the argument (or no argument) it just gives back: Status: 302 Found Location: / Cache-Control: private, no-cache="set-cookie" Expires: 0 Pragma: no-cache Content-Type: text/html; charset=utf-8 I don't know if this is related, but something else I should point out anyway: There are a couple places in web.d that call "cgi.setResponseLocation()" with two arguments (the second arg is the bool "false"). But the only setResponseLocation() in cgi.d just takes the one argument, it doesn't have a second argument. So I commented out the ", false" arg to make it compile.
Jul 14 2011
parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Nick Sabalausky wrote:
  I'm having trouble figuring out how to use the executable.
You'll need to make sure the program is set to run as CGI and that the stuff after the path is forwarded to the program. In Apache, dropping it in cgi-bin does both for you, or you can do a SetHandler cgi-script in any other location. In IIS, you go to handler mappings on your web site and add the program to the cgi handler. You might have to change cgi and api restrictions too to allow it. (IIS seems to dislike CGI but if you go through enough steps it can finally work. I don't use it often though so I don't know all the edge cases and whatnot.) If it works better with Fast CGI, I don't know if it does or not, you might be able to compile cgi.d with -version=fastcgi and get better results.
 FWIW, if I run it at the command-line, no matter what I give as
 the argument (or no argument) it just gives back:
CGI programs get info sent to them through the environment variables and stdin. (I've been meaning to add a command line alternatives but haven't gotten around to it yet.) The function to call in web.d is determined by the PATH_INFO envvar. If it's blank, it asks the browser to redirect with the trailing slash - that's the response you're seeing there. (the reason it asks for this is so relative links to functions work better.) Try setting the environment variable PATH_INFO=/ and then running the program. You should see your document spat out. Calling other functions is then done by adding more path to the url, which is again communicated through PATH_INFO. url: mysite.com/myscript/myfunction web server passes PATH_INFO=/myfunction program runs "myfunction();"
 that call
 "cgi.setResponseLocation()" with two arguments
I must have updated the public web.d but not the public cgi.d... That second argument is fairly new. It means if the redirect is important or not. The default is true. If it's false, the redirect won't overwrite any existing redirect. cgi.setResponseLocation("/mypage", true); // redirect is now mypage cgi.setResponseLocation("/other", true); // overwrites - now redirect to other cgi.setResponseLocation("/suggestion", false); // does not overwrite - this redirect is not important The not important one is useful if you want to redirect if and only if there was no other redirect already set up. Web.d uses it at the end of the user defined function as a default behavior. If your function already specified a redirect, it won't overwrite it. Grab a new copy of the module: http://arsdnet.net/dcode/cgi.d And you can see the newer parameter with some slight documentation.
Jul 14 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:ivnq7e$1244$1 digitalmars.com...
 Nick Sabalausky wrote:
  I'm having trouble figuring out how to use the executable.
[...helpful info...]
Cool, thanks. On the cmdline, setting the env PATH_INFO to / makes it work. In the browser/IIS, adding a trailing slash to the requested URL makes it work (Not sure why IIS changes the redirect's "/" to "localstart.asp", probably just IIS trying to be "smart", but I usually only use IIS locally, so I don't really care right now). And that new cgi.d works. :) Oh, one other thing I noticed: With DMD 2.054 banning implicit switch/case fallthrough, it pointed out an implicit fallthrough in dom.d at line 2641 (ie, the case "<"). All the other cases in that switch have a "break", and I noticed you do occasionally use "goto case" and "// fallthrough" in other switch statements, so I wasn't sure if that fallthrough really was intentional or not.
Jul 14 2011
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Nick Sabalausky wrote:
 (Not sure why IIS changes the redirect's "/" to "localstart.asp",
 probably just IIS trying to be "smart", but I usually only use IIS > locally,
so
I don't really care right now). It's possible I messed up... the line of code is specifically: cgi.setResponseLocation(cgi.requestUri ~ "/"); which is supposed add the slash. But maybe my requestUri member is wrong on IIS, so it saw just the slash, and that redirected to the other thing. Hmmmm, a quick web search tells me that IIS doesn't set REQUEST_URI the same way as Apache, so this is probably a bug in cgi.d. I thought that was a standard, but it looks like it might be an Apache extension. Huh, I've gotta think about this.
 Oh, one other thing I noticed: With DMD 2.054 banning implicit
 switch/case fallthrough, it pointed out an implicit fallthrough
 in dom.d at line 2641
That's interesting... I updated my dmd but didn't see this.... but yes that's definitely a bug, also in my copy of the code. Add a break to it. You might want to grab a new copy of dom.d. I think your copy is pretty old in general, since that line number is a few hundred lines different than my copy. http://arsdnet.net/dcode/dom.d The newer one has stuff like requireSelector and requireElementById that we discussed a while ago, among other things. (that dcode folder is updated on random whims. I do changes for myself in another location then copy it over usually when I talk about it on the newsgroup.) Anywho. That's embarrassing... every time bearophile mentions fallthrough, I defend it - it's sometimes useful and besides, those bugs *never* happen to *me*. Blargh. (the reason I didn't catch this before is that case is a private extension to CSS' selector, that I very, very rarely use, and nobody else uses it either, since it's nonstandard, so it hasn't been caught in my little browser I'm writing with this either.)
Jul 14 2011
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:ivo1ga$1ete$1 digitalmars.com...
 Nick Sabalausky wrote:
 (Not sure why IIS changes the redirect's "/" to "localstart.asp",
 probably just IIS trying to be "smart", but I usually only use IIS > 
 locally, so
I don't really care right now). It's possible I messed up... the line of code is specifically: cgi.setResponseLocation(cgi.requestUri ~ "/"); which is supposed add the slash. But maybe my requestUri member is wrong on IIS, so it saw just the slash, and that redirected to the other thing. Hmmmm, a quick web search tells me that IIS doesn't set REQUEST_URI the same way as Apache, so this is probably a bug in cgi.d. I thought that was a standard, but it looks like it might be an Apache extension. Huh, I've gotta think about this.
More detailed information in case it's helpful: The URL I typed into the browser was: http://localhost/darticles/articles-debug.exe According to HttpFox (FF plugin), the headers received were: HTTP/1.1 302 Object moved Server: Microsoft-IIS/5.1 Date: Fri, 15 Jul 2011 04:18:56 GMT X-Powered-By: ASP.NET Connection: close Location: localstart.asp Content-Length: 121 Content-Type: text/html Cache-Control: private Note, FWIW, that's a relative path in the "Location". Ie, it's "localstart.asp", not "/localstart.asp", so the browser then goes to http://localhost/darticles/localstart.asp If I insetad go to http://localhost/darticles/articles-debug.exe/ then it all works right. Although I guess that probably doesn't help tell you what the CGI app received from IIS...
 Oh, one other thing I noticed: With DMD 2.054 banning implicit
 switch/case fallthrough, it pointed out an implicit fallthrough
 in dom.d at line 2641
That's interesting... I updated my dmd but didn't see this.... but yes that's definitely a bug, also in my copy of the code. Add a break to it. You might want to grab a new copy of dom.d. I think your copy is pretty old in general, since that line number is a few hundred lines different than my copy. http://arsdnet.net/dcode/dom.d The newer one has stuff like requireSelector and requireElementById that we discussed a while ago, among other things.
My copy does have requireSelector and requireElementById, but yea, it looks like that latest one does have a lot of new stuff.
 (that dcode folder is updated on random whims. I do changes for
 myself in another location then copy it over usually when I talk
 about it on the newsgroup.)
Sooo...I don't suppose you've given thought to using Hg/BitBucket or Git/GitHub? ;) It'd make a lot of things much easier for both you and others using your code. And it would better facilitate people submitting patches to you. They are an extra tool to learn and use, but they're well worth it.
 Anywho.

 That's embarrassing... every time bearophile mentions fallthrough,
 I defend it - it's sometimes useful and besides, those bugs
 *never* happen to *me*.

 Blargh.
:)
Jul 14 2011
next sibling parent reply Adam Ruppe <destructionator gmail.com> writes:
Nick Sabalausky wrote:
 Sooo...I don't suppose you've given thought to using Hg/BitBucket or
 Git/GitHub? ;)

 It'd make a lot of things much easier for both you and others using
 your code.  And it would better facilitate people submitting patches
 to you. Theyare an extra tool to learn and use, but they're well
 worth it.
Easier for me is hard to see... right now, I just write files and when I want it shared, I run: cp dom.d /var/www/htdocs/dcode And that's all there is to it.. similarly, saving changes is as simple as hitting save in my editor. Revert means hitting undo a bunch of times. Basically my primitive approach is good enough, so while git (etc.) have some benefits, they aren't enough to overcome my massive inertia. Now, I do have git installed here and know the basics on how to use it, and Walter and Andrei pushed me into making a github account. What I hate about github though... SOCIAL CODING. Ugh, I see the word "social" way way WAY too much! I've come to hate it the way I hate "secure" and "powerful" - meaningless words added to garbage so it can be on the bandwagon too! but meh I did it anyway and it wasn't as painful as I thought to get started: https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff Wait a minute........ the files don't seem to actually be there! And this website is so SLOW! How annoying. Meh, I'll come back to it later. BTW, looking at my comments in web.d... note one thing: most of those are notes to self; it's a todo list of ideas, not necessarily things that actually work. I just realized I talked about command line access in a comment at the top, but none of that exists in code! It's just there so I don't forget to eventually add it.
Jul 15 2011
next sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Adam Ruppe" <destructionator gmail.com> wrote in message 
news:ivpdoo$rif$1 digitalmars.com...
 Nick Sabalausky wrote:
 Sooo...I don't suppose you've given thought to using Hg/BitBucket or
 Git/GitHub? ;)

 It'd make a lot of things much easier for both you and others using
 your code.  And it would better facilitate people submitting patches
 to you. Theyare an extra tool to learn and use, but they're well
 worth it.
Easier for me is hard to see... right now, I just write files and when I want it shared, I run: cp dom.d /var/www/htdocs/dcode And that's all there is to it.. similarly, saving changes is as simple as hitting save in my editor. Revert means hitting undo a bunch of times.
Does your undo stack persist after the editor (or the file) is closed? How big is the undo stack? How easy is to undo to a specific working (ie, not "in the middle of a task") state? Also, doing it that way makes it harder to track down where a regression was introduced. A point that was a big one for me: What happens when you decide you need to go back and use, or take a look at, some piece of code that you've already deleted? Another big thing is that it makes it much easier to fold in user-submitted changes. (And you're more likely to actually *get* other people helping out.)
 What I hate about github though... SOCIAL CODING. Ugh, I see the
 word "social" way way WAY too much!
I *completely* agree! Every time I see/hear the word "social" (at least used with an implied positive connotation) it makes my skin crawl. But then, I hate most people, I've always hated socializing (except for message boards and close friends/family), I hate highly social people, I hate Twitface and people who use it, etc... And, of course, "social" has become just as much of an idiotic, meaningless buzzword as "cloud". Unfortunately, even as much of a turn-off as "social" is, I have to admit, DVCSes are absolutely fantastic tools, and the collaboration is, admittedly, a very very good aspect. I do wish the sites weren't so damnned slow and JS-heavy, though...Hell, even with JS off, they're insanely slow when viewing code - but I blame HTML/CSS for that...
 but meh I did it anyway and it wasn't as painful as I thought to get
 started:

 https://github.com/adamdruppe/misc-stuff-including-D-programming-language-web-stuff
Cool :) Nice repo name, btw ;) BTW, Tip from experience: Save yourself the sanity and never bother trying to deal with hg-git (the thing that supposedly lets you access Git repos from Hg)...
Jul 15 2011
parent Adam Ruppe <destructionator gmail.com> writes:
Nick Sabalausky wrote:
 Does your undo stack persist after the editor (or the file) is
 closed? How big is the undo stack? How easy is to undo to a specific
 working (ie, not "in the middle of a task") state?
It /can/ do them all, though I personally only the infinitely sized undo stack part. (I use vim, which can do branched and timed undo stacks. I think it can name them too but I'm not sure) I'm also more likely to comment something out than to actually remove it.
 Another big thing is that it makes it much easier to fold in
 user-submitted changes.
Indeed, though I try to avoid those situations too!
 BTW, Tip from experience: Save yourself the sanity and never bother
 trying to deal with hg-git
I actually mostly like the git command line program.
Jul 15 2011
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Just a general comment... my D web stuff is spoiling me.

Guy just asked me for a form based file uploader. With web.d:

===
import arsd.web;
import std.file;
class SiteAdmin : ApiProvider {
    override void _initialize() { cgi.requireBasicAuth("user", "pass"); }

    string uploadNewVideo(Cgi.UploadedFile file) {
         std.file.write("desiredfile", file.content);
         return desiredfile;
    }

    override Document _defaultPage() {
         return _getGenericContainer().
            appendChild(_sitemap()).parentDocument;
    }
}
mixin FancyMain!SiteAdmin;
===

Boom. The library will auto-generate the form and some basic
html output and a list of links to the pages.

Compiling that little snipped will give me something
I could show to him *right now*. And I can expand it later with
ease. This one has a simple HTTP hard coded username and password
which works for now and can again be trivially changed later.

But alas, this job needed to be PHP. PHP is supposed to make
file uploads easy, but I have to look up the stuff every time.

(just like how I have to look up the args to PHP str_replace
every time... and I often forget Javascript substr or substring?
In D, "string".replace("this", "that")[0..5]; is trivial to
remember.)
Jul 15 2011
parent "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:ivr07p$8cq$1 digitalmars.com...
 Just a general comment... my D web stuff is spoiling me.

 Guy just asked me for a form based file uploader. With web.d:

 ===
 import arsd.web;
 import std.file;
 class SiteAdmin : ApiProvider {
    override void _initialize() { cgi.requireBasicAuth("user", "pass"); }

    string uploadNewVideo(Cgi.UploadedFile file) {
         std.file.write("desiredfile", file.content);
         return desiredfile;
    }

    override Document _defaultPage() {
         return _getGenericContainer().
            appendChild(_sitemap()).parentDocument;
    }
 }
 mixin FancyMain!SiteAdmin;
 ===

 Boom. The library will auto-generate the form and some basic
 html output and a list of links to the pages.
Cool :)
 Compiling that little snipped will give me something
 I could show to him *right now*. And I can expand it later with
 ease. This one has a simple HTTP hard coded username and password
 which works for now and can again be trivially changed later.

 But alas, this job needed to be PHP. PHP is supposed to make
 file uploads easy, but I have to look up the stuff every time.
And whatever you end up with is most likely to have a bunch of subtle problems, and could easily break if moved to another server, even if you're lucky enough to have the same exact build of PHP on the new server.
 (just like how I have to look up the args to PHP str_replace
 every time... and I often forget Javascript substr or substring?
 In D, "string".replace("this", "that")[0..5]; is trivial to
 remember.)
Slicing is such a killer feature if, like me, you've come from langauges like C/C++/Java (or PHP).
Jul 15 2011
prev sibling parent Adam Ruppe <destructionator gmail.com> writes:
I changed my symlinks to hardlinks and it seems to have worked.
So that github thingy is up to date now.

Hopefully it will be simple to keep it that way!
Jul 15 2011
prev sibling next sibling parent "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:ivo1ga$1ete$1 digitalmars.com...
 Nick Sabalausky wrote:
 Oh, one other thing I noticed: With DMD 2.054 banning implicit
 switch/case fallthrough, it pointed out an implicit fallthrough
 in dom.d at line 2641
That's interesting... I updated my dmd but didn't see this....
I don't remember, but it might have been because I compile with -wi
Jul 14 2011
prev sibling parent reply "Nick Sabalausky" <a a.a> writes:
"Adam D. Ruppe" <destructionator gmail.com> wrote in message 
news:ivo1ga$1ete$1 digitalmars.com...
 Nick Sabalausky wrote:
 Oh, one other thing I noticed: With DMD 2.054 banning implicit
 switch/case fallthrough, it pointed out an implicit fallthrough
 in dom.d at line 2641
That's interesting... I updated my dmd but didn't see this.... but yes that's definitely a bug, also in my copy of the code. Add a break to it.
I might have found another one in the new dom.d. Starting at line 3006 it has: case "visited": case "active": case "hover": case "target": case "focus": case "checked": case "selected": current.attributesPresent ~= "nothing"; // FIXME /* // defined in the standard, but I don't implement it case "not": */ /+ // extensions not implemented //case "text": // takes the text in the element and wraps it in an element, returning it +/ case "before": case "after": current.attributesPresent ~= "FIXME"; The "visited"/"selected" case falls through into the "before"/"after" case. Looks like that might not be intended, but I could be wrong...
Jul 14 2011
parent reply Adam Ruppe <destructionator gmail.com> writes:
Nick Sabalausky wrote:
 I might have found another one in the new dom.d. Starting at line
 3006 it has:
Nah, that's just not implemented. The reason those cases are there is the browser app would throw an exception on it (assert(0) I believe) if it didn't recognize the names, but those are common in real websites. So I put the cases in then just some spam.. I was going to do something with attributes then changed my mind then changed it again... but regardless none of it actually does anything so it doesn't matter what it says. (The difficulty I'm having there is I really want it to throw on not implemented or unknown stuff, but I also want it to be able to handle the kind of pure putrid shit you find on the open internet. Document has a flag to parse() for that - loose vs strict, but the css handler is half used for getElementsBySelector and half garbage so it doesn't have a consistent approach at all.)
Jul 15 2011
parent reply "Nick Sabalausky" <a a.a> writes:
"Adam Ruppe" <destructionator gmail.com> wrote in message 
news:ivp9aq$jn4$1 digitalmars.com...
 (The difficulty I'm having there is I really want it to throw on
 not implemented or unknown stuff, but I also want it to be able to
 handle the kind of pure putrid shit you find on the open internet.
Yea, I've been having to deal with that on a big Haxe project I've been working on. I have a nice spiffy automatic error-reporting system, but it's proven surprisingly hard to find the right balance between what should be reported and what would just be noise. Speaking of, apparently, HTTP's HEAD command is technically required by the HTTP spec to work right. But my system hasn't been handling it (I didn't even know about it before), and I never had *anyone* actually send such a request. But just recently I started getting one HEAD request every few days from an IP that've traced to Amazon WebSevices, which makes me wonder what the hell someone is even trying to do. The site is a demonstration for a memory-exercise program I've been tech lead on ( www.attentionworkout.com - pardon the annoying parts of the site, like the embedded sound, it was designed to be used in nursing homes ), so I can't imagine what the hell anyone at Amazon WebServices would be doing with it. But, HEAD is technically required (though I have no idea what the real-world use-cases are), so I'm not quite sure what to do.
 Document has a flag to parse() for that - loose vs strict, but the
 css handler is half used for getElementsBySelector and half garbage
 so it doesn't have a consistent approach at all.) 
Jul 15 2011
parent Adam Ruppe <destructionator gmail.com> writes:
Nick Sabalausky wrote:
 But, HEAD is technically required (though I have no idea what the
 real-world use-cases are), so I'm not quite sure what to do.
Actually, I'd be surprised if your web server didn't handle it... it can just send a GET to your app then simply discard the response body. As for use, I think it's actually a carryover from http 1.0, rendered almost useless in http 1.1 thanks to it's conditional get. I believe they weren't in 1.0, so if you wanted to check for a new version of a page, instead of saying "get if modified since", you'd do a HEAD and check the last modified header yourself, then issuing a separate GET if it's old enough. Obviously, a conditional get is a much better way to do it. The only two things I find HEAD useful for myself are: a) testing. It's nice to be able to manually do a request and not be spammed by a million lines of body when I just want to see headers. b) making sure a file is a reasonable size before downloading. Since content-length is one of the headers in this, you can check the size and present it to the user to cancel if it's unreasonable. I don't think there's another way to do (b) in the 1.1 version. It's definitely how I'd do it.
Jul 15 2011
prev sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
Let me list some of the newer features in web.d too, added in
the last couple weeks.

class ApiObject;

These let you expose a more object oriented interface to your
stuff on the url.

====
class User : ApiObject {
   this(Foo foo, string id) {}
}

class Foo : ApiProvider {
   alias User user;
}
=====

Now, when the user goes to:

yoursite.com/yourapp/user/username

It instantiates one of those User classes, passing "username"
as the second argument to the constructor.

Then, you can add methods to your ApiObject and call them with
additional slashes on the url. Or, you can put in methods
with the name of an HTTP operation to apply straight to it.

string GET() { return "my name"; }

Now the url above works, running this GET() method. Or, you can
issue HTTP POST to it, and it runs POST() {}. Etc. The return
value is auto-formatted like with any other method.

You can also put in normal methods.

yoursite.com/yourapp/user/username/method

runs

new User(foo, "username").method();



This function is new and not fleshed out totally. The basics work,
but the javascript access isn't done yet - only top level procedures
are auto generated at this point. Basic reflection is working but
not even the sitemap uses it.

Eventually, I want to add proper support for static methods so
you can do things like get lists too, without requiring an
identifier.

That's another new method in the base class: sitemap. It lists
links to your functions. Nothing fancy, but soon I'll change
defaultPage to point to it, so creating a simple site is almost
fully automated.


Another new thing is you can now add aliases to other ApiProvider
children to your main one.

class Admin : ApiProvider { ... }

class Site : ApiProvider { alias Admin admin; }

Now, you can access the members of admin by going to
yoursite.com/yourapp/admin/methods...


This lets you separate out modules more easily. While they all
need to be aliased into the root apiprovider you provide, they
can be implemented in different modules.


It might be a good idea to make your own:

class YourApiProvider : ApiProvider {
 // override some of the methods here for a consistent site...
}

class Site : YourApiProvider {}
class Admin : YourApiProvider {}


Then you can easily have a centralized getDocument and postProcess
thing with normal overriding.


I'm considering automating that by making a chain of postProcess
calls based on where the aliases appear. Run the inner postprocess
first, then the outer one. I haven't decided yet.



You'll notice that I use alias a lot here. You don't strictly
have to, but I like to have the implementation easily separated,
which alias allows, and for the public name to not always match
the internal name (seen here with captialization). So that works
too with alias.


Another new thing is _initialize vs _initializePerCall, meant
to give more flexibility in a FastCGI situation. Using regular
CGI, it doesn't really matter since the process only handles one
call anyway.


I think that's everything recent.


Eventually I should write this documentation somewhere other
than the newsgroup!
Jul 14 2011
parent reply "RedX" <guibufolo+dlang gmail.com> writes:
On Friday, 15 July 2011 at 01:00:51 UTC, Adam D. Ruppe wrote:
 Let me list some of the newer features in web.d too, added in
 the last couple weeks.

 class ApiObject;

 These let you expose a more object oriented interface to your
 stuff on the url.

 ====
 class User : ApiObject {
    this(Foo foo, string id) {}
 }

 class Foo : ApiProvider {
    alias User user;
 }
 =====

 Now, when the user goes to:

 yoursite.com/yourapp/user/username

 It instantiates one of those User classes, passing "username"
 as the second argument to the constructor.

 Then, you can add methods to your ApiObject and call them with
 additional slashes on the url. Or, you can put in methods
 with the name of an HTTP operation to apply straight to it.
is this still working on the latest git (2bfdccc)? I don't seem to be able to call anything.. And do public functions really require "export" now or am i just declaring them in i wrong way? class MySite : ApiProvider { export string hello(string name){ return "Welcome " ~ name ~ "!"; } export string foo(){ return "foo"; } override Document _defaultPage() { return _getGenericContainer().appendChild(_sitemap()).parentDocument; } }; mixin FancyMain!MySite;
Jul 03 2013
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 3 July 2013 at 09:24:03 UTC, RedX wrote:
 is this still working on the latest git (2bfdccc)? I don't seem 
 to be able to call anything..
I found the bug, I had a static if that was too restrictive and stopped reading the child object functions. It is fixed now on the newest github version. The regular functions and child ApiProviders are still working, though the child ApiObject thing is mildly buggy, the initialize and initializePerCall aren't always done right, so if you override them, you need to call the parent too. Or something like that, I have it working in a program but it was a bug workaround hack. Regular functions work excellently though!
 And do public functions really require "export" now or am i 
 just declaring them in i wrong way?
Yes, they need export now. You can easily work around it by writing class MySite : ApiProvider { export: string hello() {} // etc } The export: at the top will apply to everything unless you override it on a specific function. The reason it does this is to get more control over if you want helper functions to show up publicly or not. Before it used a leading _ in the name to skip, which still works, but now you can also use other access specifiers. It uses export instead of public because public is available to other modules, export I took to mean even more available to outside the program.
Jul 03 2013
parent "RedX" <guibufolo+dlang gmail.com> writes:
On Wednesday, 3 July 2013 at 13:05:27 UTC, Adam D. Ruppe wrote:
 On Wednesday, 3 July 2013 at 09:24:03 UTC, RedX wrote:
 is this still working on the latest git (2bfdccc)? I don't 
 seem to be able to call anything..
I found the bug, I had a static if that was too restrictive and stopped reading the child object functions. It is fixed now on the newest github version. The regular functions and child ApiProviders are still working, though the child ApiObject thing is mildly buggy, the initialize and initializePerCall aren't always done right, so if you override them, you need to call the parent too. Or something like that, I have it working in a program but it was a bug workaround hack. Regular functions work excellently though!
 And do public functions really require "export" now or am i 
 just declaring them in i wrong way?
Yes, they need export now. You can easily work around it by writing class MySite : ApiProvider { export: string hello() {} // etc } The export: at the top will apply to everything unless you override it on a specific function. The reason it does this is to get more control over if you want helper functions to show up publicly or not. Before it used a leading _ in the name to skip, which still works, but now you can also use other access specifiers. It uses export instead of public because public is available to other modules, export I took to mean even more available to outside the program.
Very nice, thank you. I was wondering if there is a way of sending the program back to the form entry page if validation on the input fails in the function that is accepting the arguments. In the _Form function i'm only able to create the form but no validation can be done there and no _Validate automatism seems to exist, or am i overseeing something?
Jul 04 2013
prev sibling next sibling parent Adam Ruppe <destructionator gmail.com> writes:
Oh I forgot to mention what it *doesn't* do - session handling. Over
the last year and a half that I've been using it for real sites every
day, I just haven't felt the need for that beyond the most basic
cookie thing and the database.

If I need something like a session, I've always just done it in the
database, with specific table structures for that app.

I've considered doing a struct serializer or something, but meh, I
like it well enough the way it is now.
Jul 14 2011
prev sibling parent =?iso-8859-1?Q?Robert_M._M=FCnch?= <robert.muench robertmuench.de> writes:
On 2011-07-14 13:21:32 +0200, Trass3r said:

 http://arsdnet.net/dcode/
Thanks (for this link and the other related posts). I'll give it a try and play around with it. The session stuff can be kept simple via cookies or a REST interface ID. -- Robert M. Münch http://www.robertmuench.de
Jul 15 2011
prev sibling next sibling parent reply Long Chang <changedalone gmail.com> writes:
I create one , fastcgi & template is done , but I need dynamic link lib of
posix support , http://d.puremagic.com/issues/show_bug.cgi?id=6014 also
block the jade template engine .

https://github.com/sleets/oak
Jul 14 2011
parent reply =?iso-8859-1?Q?Robert_M._M=FCnch?= <robert.muench robertmuench.de> writes:
On 2011-07-14 16:00:33 +0200, Long Chang said:

 I create one , fastcgi & template is done , but I need dynamic link lib 
 of posix support , ...
I'll take a look at the fastcgi stuff. IMO it makes sense to use this to reduce process creation times. -- Robert M. Münch http://www.robertmuench.de
Jul 15 2011
parent reply Adam Ruppe <destructionator gmail.com> writes:
 IMO it makes sense to use this to reduce process creation times.
Process creation is a very small cost with D programs. It's nothing to worry about unless you have real world data to the contrary for your project. My cgi.d though supports standard cgi, fast cgi, and an embedded http server, if you have the right add on libraries. (The C language fast cgi lib available from the fast cgi people or my netman.d and httpd.d for the embedded. Of those two, I recommend fastcgi - my thing is actually faster, but less reliable and potentially insecure.) The app side interface is identical in any case, so switching out is as simple as a recompile.
Jul 15 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 7/15/11 4:26 PM, Adam Ruppe wrote:
 IMO it makes sense to use this to reduce process creation times.
Process creation is a very small cost with D programs. It's nothing to worry about unless you have real world data to the contrary for your project.
Doesn't that apply more to Unix than to D? One of the paradigm shifts incurred when I moved to Unix from Windows was how incredibly cheap it was to create processes on Unix, and how many great idioms derive from that. In Windows one gets used to thinking creating a process is a big deal, which requires a fair amount of unlearning. Andrei
Jul 15 2011
next sibling parent Trass3r <un known.com> writes:
 One of the paradigm shifts incurred when I moved to Unix from Windows  
 was how incredibly cheap it was to create processes on Unix, and how  
 many great idioms derive from that. In Windows one gets used to thinking  
 creating a process is a big deal, which requires a fair amount of  
 unlearning.
So true.
Jul 15 2011
prev sibling next sibling parent Adam D. Ruppe <destructionator gmail.com> writes:
Andrei Alexandrescu wrote:
 Doesn't that apply more to Unix than to D?
Somewhat, though a lot of the CGI flames from the day were coming from unix machines. There's two factors (I speculate) that contributed to it: a) Linux used to be slower at forking and execing than it is now. b) Most cgi apps were Perl, which meant starting up the interpreter, compiling the file, etc. in addition to the fork/exec. (b) is where the difference with D comes in - it's already compiled, so no need to take that extra step.
Jul 15 2011
prev sibling parent reply "Paulo Pinto" <pjmlp progtools.org> writes:
On Friday, 15 July 2011 at 22:37:00 UTC, Andrei Alexandrescu 
wrote:
 On 7/15/11 4:26 PM, Adam Ruppe wrote:
 IMO it makes sense to use this to reduce process creation 
 times.
Process creation is a very small cost with D programs. It's nothing to worry about unless you have real world data to the contrary for your project.
Doesn't that apply more to Unix than to D? One of the paradigm shifts incurred when I moved to Unix from Windows was how incredibly cheap it was to create processes on Unix, and how many great idioms derive from that. In Windows one gets used to thinking creating a process is a big deal, which requires a fair amount of unlearning. Andrei
On the other hand threading is everywhere.
Jul 03 2013
next sibling parent reply "Dicebot" <public dicebot.lv> writes:
On Wednesday, 3 July 2013 at 09:39:43 UTC, Paulo Pinto wrote:
 On the other hand threading is everywhere.
On the other hand both creating process and thread are so much more expensive than not creating anything at all :P
Jul 03 2013
parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Wednesday, 3 July 2013 at 09:45:18 UTC, Dicebot wrote:
 On the other hand both creating process and thread are so much 
 more expensive than not creating anything at all :P
I recently added a process pool to cgi.d and it was both the simplest and the fastest option for the http server it has. I tried to do a thread pool, to avoid creating stuff in the main loop, but I messed it up. The process pool on Linux though was dead easy and worked really well. I find it kinda interesting how threads in D seem to emulate processes too, with TLS giving you a sort of separate address space - just easier to get right as the programmer I guess.
Jul 03 2013
parent "Dicebot" <public dicebot.lv> writes:
On Wednesday, 3 July 2013 at 13:31:56 UTC, Adam D. Ruppe wrote:
 The process pool on Linux though was dead easy and worked 
 really well. I find it kinda interesting how threads in D seem 
 to emulate processes too, with TLS giving you a sort of 
 separate address space - just easier to get right as the 
 programmer I guess.
That is essentially what happens now in vibe.d when multiple worker threads are used - because all server stuff is stored in TLS, each worker thread operates completely independently, similar to separate processes but with a nice bonus of sharing data made easier in user code. I was referring to the reason behind async models became so popular though - most efficient way to deal with processes and threads is to not use them for multitasking at all :)
Jul 03 2013
prev sibling parent reply Russel Winder <russel winder.org.uk> writes:
On Wed, 2013-07-03 at 11:39 +0200, Paulo Pinto wrote:
[=E2=80=A6]
 On the other hand threading is everywhere.
Threads (and processes) are like stacks and heaps, you know they are there but if you are manipulating them explicitly instead of as a managed resource, you need to have a very, very good reason why. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Jul 03 2013
parent Paulo Pinto <pjmlp progtools.org> writes:
Am 03.07.2013 12:03, schrieb Russel Winder:
 On Wed, 2013-07-03 at 11:39 +0200, Paulo Pinto wrote:
 […]
 On the other hand threading is everywhere.
Threads (and processes) are like stacks and heaps, you know they are there but if you are manipulating them explicitly instead of as a managed resource, you need to have a very, very good reason why.
True, but functional programming is only now becoming mainstream. I remember reading a book around 1997 about doing HPC in multicore machines with NUMA in a Lisp like language. The language runtime was the OS and it took care of exploring the multicore environment, while the researchers could express higher level algorithms. Eventually we will get there. -- Paulo
Jul 03 2013
prev sibling next sibling parent Robert Clipsham <robert octarineparrot.com> writes:
On 14/07/2011 11:49, Robert M. Münch wrote:
 Hi, is there a matured framework for building the server side part of
 web-apps in D2? I don't need totally fancy things, session handling,
 dynamic content and simple output generation.
I recommend Adam's given that he's using it in production. I should also note that I'm working on a framework at: https://github.com/mrmonday/serenity The lack of commits recently is due to my work on a D->JavaScript compiler in addition to being rather busy. -- Robert http://octarineparrot.com/
Jul 14 2011
prev sibling next sibling parent "Masahiro Nakagawa" <repeatedly gmail.com> writes:
Hi Robert,

On Thu, 14 Jul 2011 19:49:10 +0900, Robert M. M=C3=BCnch  =

<robert.muench robertmuench.de> wrote:

 dynamic content and simple output generation.
In this point, I implement simple template engine called Mustache(Pure D= = and single file). https://bitbucket.org/repeatedly/mustache4d/overview Sorry, I don't have other libraries. Masahiro
Jul 14 2011
prev sibling parent Martin Nowak <code dawg.eu> writes:
On 07/14/2011 12:49 PM, Robert M. Münch wrote:
 Hi, is there a matured framework for building the server side part of
 web-apps in D2? I don't need totally fancy things, session handling,
 dynamic content and simple output generation.
http://vibed.org/
Jul 06 2013