templates.index.html Maven / Gradle / Ivy
{#==========================================
Index
==========================================#}
{% extends "./layout.html" %}
{% block sectionClasses %}index{% endblock %}
{% block meta_title %}Java web framework{% endblock %}
{% block meta_description %}Highly Flexible Java Web Framework Based On Guice{% endblock %}
{% block body %}
     
        
		    
		        Propulsion for your web backend
		        Spincast is an highly flexible 
                and open source Java web framework, based on Guice.
		    
	    
    
     
    
        {#==========================================
        Main content
        ==========================================#}
        
        
            
            
		        {#==========================================
		        Spincast overview
		        ==========================================#}
                
                    
                        
                        Spincast overview
                    
                    
                    
                        Spincast is a Java framework to serve as a backend for Single Page Applications (SPA),
                        to develop old-school HTML generated websites
                        or even to be a REST web service / microservice platform, as it speaks Json
                        and XML natively. It is made of a small core and a plugins 
                        ecosystem. It aims to be as flexible and enjoyable as possible, but not to be simple 
                        at all cost!
                    
 
                    
                        Simple things should be simple, complex things should be possible.
                        
                    
                    
                        Sane defaults are provided for pretty much all parts of the framework, but everything is 
                        overridable/configurable. For example, there are no private methods in the
                        framework, the default method visibility is protected 
                        (learn more). 
                        Spincast is built from the ground up using the wonderful 
                        Guice
                        and the  modularity features this library provides. It uses an embedded HTTP server so it's easy 
                        to develop, test and deploy. 
                    
 
                    
                        Configuration over convention!
                    
                    
                        Spincast is not the kind of microframeworks that quickly produces one-liner applications. There are
                        no static methods, no magical conventions, no easy shortcuts. In our opinion, developers should 
                        always keep total control over what's going on, even if that requires a little bit more work 
                        from their part and some extra lines of code.
                    
                    
                    
                
                
                {#==========================================
                Hello World (quick version)
                ==========================================#}
                
                    
                    
	                    
	                    Hello World! (quick and dirty version)
                    
                    
                        
                        First, you add the latest version of the org.spincast:spincast-default
                        Maven artifact to your pom.xml (or build.gradle) :
                        
                            
                                
<dependency>
    <groupId>org.spincast</groupId>
    <artifactId>spincast-default</artifactId>
    <version>{{spincastCurrrentVersion}}</version>
</dependency> 
                            
                            
                            
  
                        
                    
                    
                        
                        Then you bootstrap everything using a main(...) method :
                        
                            
                                
public class App {
    public static void main(String[] args) {
        Injector guice = Guice.createInjector(new SpincastDefaultGuiceModule(args));
        IDefaultRouter router = guice.getInstance(IDefaultRouter.class);
        
        router.GET("/").save(context -> context.response().sendPlainText("Hello World!"));
        guice.getInstance(IServer.class).start();
    }
} 
                            
                            
                                Explanation :
                                (Tip : try hovering/clicking the page numbers below!)
                                
                                    - 
                                        3 : A good old Java's 
main(...) method! This
                                        is the entry point of a standard Spincast application.
                                     
                                    - 
                                        5 : The very first thing a Spincast application
                                        does is to create a Guice context. Here, we use the provided
                                        
SpincastDefaultGuiceModule module. This module binds a default
                                        implementation for all the required components of a Spincast application.
                                     
                                    - 
                                        7 : We get the default router (
IDefaultRouter) from Guice.
                                     
                                    - 
                                        9 : We add a 
GET route for the 
                                        "/" index page, using a Java 8's lambdas syntax. 
                                         This inline route handler sends a plain text "Hello World!" message to the user.
                                     
                                    - 
                                        11 : We get the HTTP server (
IServer) from Guice and
                                        we start it!
                                     
                                
                             
                            
                               Now, if you would point your browser to http://localhost:44419 
                               (Spincast default port is 44419), you should see the
                               "Hello World!" message.
                            
 
                        
                    
                    
                        
                        Here's the exact same example but using Java 7, so without lambdas. We prefer this version
                        for a first example because the types of the various components are more obvious!:
                    
                    
                        
                            
                                
public class App {
    public static void main(String[] args) {
        Injector guice = Guice.createInjector(new SpincastDefaultGuiceModule(args));
        IDefaultRouter router = guice.getInstance(IDefaultRouter.class);
        router.GET("/").save(new IDefaultHandler() {
            @Override
            public void handle(IDefaultRequestContext context) {
                context.response().sendPlainText("Hello World!");
            }
        });
        guice.getInstance(IServer.class).start();
    }
} 
                            
                            
                                Explanation :
                                
                                    - 
                                        9-14 : We can now clearly see that the
                                        
save(...) method in fact takes a route handler as a parameter.
                                        In this simple example, the route handler is declared inline using the 
                                        IDefaultHandler interface. We'll learn more about route handlers in the
                                        next example. 
                                     
                                
                             
                        
                    
                
                
                {#==========================================
                Hello World (more scalable version)
                ==========================================#}
                
                    
                        
                        Hello World! (more scalable version)
                    
                    
                        We're not big fans of those very short "Hello world!" examples because, in real life, you
                        usually don't develop such basic applications. You want an architecture that 
                        is flexible and scalable! So, let's use a more flexible structure now.
                    
                    
                        In this second example we'll:
                        
                        
                            - 
                                Make the 
App class itself being managed by Guice.
                             
                            - 
                                Use a custom Guice module.
                            
 
                            - 
                                Learn how to extend the 
request context type.
                             
                        
                    
                    
                        
                        If you look carefully, in the previous example we used a lot of Default components
                        ("IDefaultRouter" for example). 
                        Those Default components are useful to have a quick up and running Spincast application. 
                        But they hide the fact that they 
                        represent objects that are actually parameterized. In Spincast, most of the components related to 
                        the routing process are parameterized with the request context type. You can learn more about
                        this topic in the The Request Context 
                        section of the documentation, but we'll introduce it briefly here.
                    
   
                    
                        A request context is the object Spincast passes to the matching route handlers
                        when a request arrives. This object allows your handlers to access information
                        about the current request (its body, headers, path parameters, etc.) and
                        to build the response that is going to be sent back (its body, headers, http status, etc.).
                        But there are also more generic utility methods on the request context, methods not directly
                        related to the request or the response. Here's a quick example :
                    
  
                    
                        
                            {% verbatim %}
public void myHandler(IDefaultRequestContext context) {
    Map<String, Object> params = new HashMap<String, Object>();
    params.put("name", "Stromgol");
    String result = context.templating().evaluate("Hello {{name}}", params);
    
    // Do something with the result...
}{% endverbatim %}
                        
                            
                                Explanation :
                                
                                    - 
                                        5 : The 
templating() "method"
                                        is not directly related to the request or the response. 
                                        It's an add-on that provides utilities to the 
                                        route handlers.
                                     
                                
                              
                    
                    
                        
                        In our first "Hello World" example, the request context type was IDefaultRequestContext, 
                        which is the default.
                        In Spincast, this default type can be extended, you can add extra
                        functionalities to it! Those functionalities can be simple methods or full objects, 
                        called add-ons. Most of the time, those add-ons are provided by
                        plugins.
                    
  
                    
                        But why would we want to extend the request context? 
                    
  
                    
                        Imagine a plugin
                        which job is to manage authentification and autorization. Wouldn't it be nice if
                        this plugin could add some extra functionalities to the request context? 
                        For example :   
                    
  
                    
                        
                            
                                
router.GET("/").save(new IDefaultHandler() {
    @Override
    public void handle(IDefaultRequestContext context) {
        if(context.auth().isAuthenticated()) {
            String username = context.auth().user().getUsername();
            // ...
        }
    }
}); 
                             
                        
                    
                    
                        This is what being able to extend the request context allows.
                    
                    
                        
                        So in this new and improved "Hello world!" example, we're going to use a custom
                        request context type: IAppRequestContext. We're going to add a simple method 
                        to it : translate(String sentence, Locale from, Locale to),
                        which job will be to translate a sentence from one language to another. By adding this
                        new method to our custom request context type, our route handlers will have
                        easy access to it.
                    
                    
                        
                        Note that, for this second example, we still have to include the org.spincast:spincast-default
                        Maven artifact because, even if we'll use a custom request context type,  we'll still be
                        using all the other default components (the default HTTP server, for example).
                    
                    
                        
                        Let's first have a look at what our new App class will be. We'll create the other
                        required components after.
                        
                        
                            
                                
public class App {
    public static void main(String[] args) {
        Injector guice = Guice.createInjector(new AppModule());
        App app = guice.getInstance(App.class);
        app.start();
    }
    private final IServer server;
    private final IRouter<IAppRequestContext> router;
    @Inject
    public App(IServer server, IRouter<IAppRequestContext> router) {
        this.server = server;
        this.router = router;
    }
    public void start() {
        this.router.GET("/").save(new IHandler<IAppRequestContext>() {
            @Override
            public void handle(IAppRequestContext context) {
                String translated = context.translate("Hello World!", 
                                                      Locale.ENGLISH, 
                                                      Locale.FRENCH);
                context.response().sendPlainText(translated);
            }
        });
        this.server.start();
    }
} 
                            
                            
                                Explanation :
                                
                                    - 
                                        1 : The 
App class is still the
                                        entry point of our application but, in this new example, it is also going to 
                                        be part of the Guice context!
                                     
                                    - 
                                        5 : Instead of using the default 
                                        
SpincastDefaultGuiceModule Guice module provided by Spincast, we
                                        use a custom Guice module, AppModule (listed below).
                                     
                                    - 
                                        7-8 : When the Guice context is created, we
                                        get the 
App instance and we call its start() method.
                                        As you'll see, we'll bind the App class itself in our
                                        custom AppModule module, so Guice manages it!
                                     
                                    - 
                                        14-18 : Since the 
App instance is
                                        managed by Guice, all the required dependencies will be automatically injected
                                        in its constructor. Here, we inject the HTTP server (IServer) and
                                        a custom and parameterized router: IRouter<IAppRequestContext>.
                                        We'll see that because the router is parameterized with a custom 
                                        request context type, "IAppRequestContext", our route handler will
                                        have access to a new translate(...) method...
                                     
                                    - 
                                        20 : The 
start() method called 
                                        at line 8, once
                                        Guice context is created.
                                     
                                    - 
                                        22 : We add a 
GET route for the "/" index page.
                                        Here, we won't use Java 8 lambdas or method handles so you can clearly see
                                        the types involved. Since the router, IRouter<IAppRequestContext>, is parameterized with our custom 
                                        request context type, the handler type,
                                        IHandler<IAppRequestContext>, will also be.
                                     
                                    - 
                                        25 : The 
handle(...) method receives an
                                        instance of our
                                        custom request context type, "IAppRequestContext".
                                     
                                    - 
                                        26-28 : We can now use our new 
                                        
translate(...) method, available directly on the request context
                                        object!
                                     
                                    - 
                                        33 : We start the server.
                                    
 
                                
                              
                        
                      
                    
                        
                        Now that we looked at the new App class, let's create our custom IAppRequestContext 
                        type in which the new translate(...) method will be defined :
                        
                            
                                
public interface IAppRequestContext extends IRequestContext<IAppRequestContext> {
    public String translate(String sentence, Locale from, Locale to);
    // Other custom methods and/or add-ons...
} 
                            
                            
                                Explanation :
                                
                                    - 
                                        1 : A custom 
request context interface
                                        must extend the IRequestContext base interface and parameterize it
                                        using its own type. To learn more about this, check the 
                                        Extending the default request context type
                                        section of the documentation.
                                     
                                    - 
                                        3 : We declare our custom 
translate(...) method.
                                      
                                
                              
                        
                    
                     
                    
                        
                        Then, let's add an implementation for this interface :
                        
                            
                                
public class AppRequestContext extends RequestContextBase<IAppRequestContext>
                               implements IAppRequestContext {
    @AssistedInject
    public AppRequestContext(@Assisted Object exchange) {
        super(exchange);
    }
    @Override
    public String translate(String sentence, Locale from, Locale to) {
        // Ok, it's more hardcoded than translated for now!
        return "Salut, monde!";
    }
} 
                            
                            
                                Explanation :
                                
                                    - 
                                        1-2 : Our 
                                        implementation class extends the 
RequestContextBase
                                        class to keep all the functionalities of the default
                                        request context, but also implements
                                        our custom IAppRequestContext interface, where our new
                                        translate(...) method is declared.
                                     
                                    - 
                                        4-7 : The constructor is annotated with
                                        
@AssistedInject because it will be used by a Guice
                                        assisted factory.
                                        Don't worry too much about this or about the exchange parameter, 
                                        the latter is simply required by the parent class's constructor.
                                     
                                    - 
                                        9-14 : A dummy implementation of our new
                                        method, 
translate(...). 
                                      
                                
                              
                        
                    
                    
                    
                        
                        Finally, we bind everything together by creating a custom 
                        Guice module,  AppModule. This module is the one
                        used by our App class to create the Guice context.
                        
                            
                                
public class AppModule extends SpincastDefaultGuiceModule {
    @Override
    protected void configure() {
        super.configure();
        bind(App.class).in(Scopes.SINGLETON);
    }
    @Override
    protected Class<? extends IRequestContext<?>> getRequestContextImplementationClass() {
        return AppRequestContext.class;
    }
    
} 
                            
                            
                                Explanation :
                                
                                    - 
                                        1 : Our custom module extends 
                                        
SpincastDefaultGuiceModule since we want to keep the
                                        default bindings and only tweak a few things.
                                     
                                    - 
                                        6 : In the overidden 
configure()
                                        method, we bind our App class itself! That way, Guice knows about it
                                        and is able to inject the dependencies it requires.
                                     
                                    - 
                                        9-12 : We override the 
                                        
getRequestContextImplementationClass() method to let Spincast know that
                                        it has to use our custom
                                        AppRequestContext request context type instead of the default one!
                                        Note that Spincast will automatically find the associated IAppRequestContext
                                        interface and will use it to parameterize the router and the other routing
                                        related components.    
                                       
                                
                              
                        
                    
                    
                        And that's it! If you start this application (using the main(...) method of
                        the App class) and point your browser to
                        http://localhost:44419, you'll see "Salut, monde!".
                    
    
                       
                        Extending the request context type may seem like a lot of code! 
                        But once in place, adding new functionalities is pretty easy. And you'll have a solid and flexible 
                        base to build your application.
                     
  
                        
                        That said, if it's too much, you can also start using 
                        Spincast with the provided default components and only switch to custom ones 
                        when you feel ready...
                    
                    
                        Note that if you use the Quick Start
                        application as a start, the customization of
                        the request context type has already been done for you.
                    
   
                
                
                {#==========================================
                Hello World (real life version)
                ==========================================#}
                
                    
                    
                        
                        Hello World! (real life version)
                    
                    
                        Our second example was a good step forward. But in a real life application, your logic
                        wouldn't all be inside a single App class! You would have controllers,
                        services, respositories, etc.
                    
                    
                        Make sure you read the Bootstrapping your app section
                        of the documentation for more ideas on how to structure a real life Spincast application.
                    
                
                
                {#==========================================
                Next steps
                ==========================================#}
                
                    
                        
                        Where to go from here?
                    
                    
                        If you haven't done so yet, try the Quick Start
                        application. Not only it is a good way to learn how a Spincast application works,
                        but it also makes a good starting point to build a real application. Open the project
                        in your favorite IDE, add breakpoints and start debugging: this is probably the best way 
                        to really learn how Spincast works.
                    
                    
                        Finally, if you feel really adventurous, you could even 
                        Read The Freaking Manual!
                    
                
            
        
        
        {#==========================================
        Right sidebar
        ==========================================#}
         {# End right-sidebar #}
     {# End row #}
    
 
{% endblock %}