Skinny Framework


Logo

GitHub Stats


What’s Skinny?


Skinny is a full-stack web app framework built on Scalatra.

To put it simply, Skinny framework’s concept is Scala on Rails. Skinny is highly inspired by Ruby on Rails and it is optimized for sustainable productivity for Servlet-based web app development.

What’s more, Skinny’s components are basically independent from Skinny app environment. If you prefer using only Skinny ORM, Validator module or else, it’s also possible. We hope Skinny components help developers that use other frameworks too.

Why Skinny named as Skinny? What does the name Skinny actually mean? We have three reasons as follows.

Application should be skinny

All the parts of a web application - controllers, models, views, routings and other settings - should be skinny. If you use Skinny framework, you can do without a lot of non-essential boilerplate code. For instance, when you create a simple registration form, all you need to do is define the parameters and validation rules and create view templates in an efficient way (ssp, scaml, jade, FreeMarker or something else) in most cases.

Framework itself should be skinny

Even if you need to investigate Skinny’s internals, don’t worry. Skinny keeps itself skinny, too. We believe that if the framework is well-designed, the resulting implementation will be skinny.

'su-ki-ni' in Japanese means 'as you like it'

A sound-alike word “好きに (su-ki-ni)” in Japanese means “as you like it”. This is only half kidding but it also represents Skinny’s concept. Skinny framework should provide flexible APIs to empower developers as much as possible and shouldn’t get in the way.


Try It Right Now


Download skinny-blank-app(-with-deps).zip and unzip it, then just run ./skinny (or skinny.bat) command on your terminal. That’s all!

If you’re a Scala beginner, skinny-blank-app-with-deps.zip is highly recommended. This is a bootstrap package which includes all library dependencies.

Don’t waste your passion by waiting for the download to complete!

If you’re already familiar with Scala and your sbt.ivy.home directory has lots of assets, use skinny-blank-app.zip instead.


1) skinny-blank-app-with-deps.zip (85MB)

For begineers, this one is highly recommended because you don’t need to wait download dependencies.

Download

2) skinny-blank-app.zip (1MB)

If you’re a heavy Scala user, this one will be suitable for you.

Download

3) Homebrew

If you’re a MacOS X user, take a look at our Homebrew formula.


Homebrew


If you’re a MacOS X user, try our Homebrew formula out.

https://github.com/Homebrew/homebrew/blob/master/Library/Formula/skinny.rb

brew update
brew install skinny

skinny new skinny-blank-app
cd skinny-blank-app
skinny run

If you sufferred the following error, try brew uninstall node && brew install node --with-npm (in some cases, also need to rm -rf /usr/local/lib/node_modules).

npm is required. If you have installed node with `--without-npm` option, reinstall with `--with-npm`.

After unzipping blank-app.zip, Let’s create our first Skinny app by using the scaffold generator.

# If you're a zsh user, try "noglob ./skinny g scaffold ..."
./skinny g scaffold members member name:String activated:Boolean luckyNumber:Option[Long] birthday:Option[LocalDate]
./skinny db:migrate

# When you use IDE's debugger, use "./skinny debug" instead. (default JDWP port is 5005)
./skinny run

If you prefer Scalate templates precompilation, specify -precompile option too.

./skinny run -precompile

And then, access http://localhost:8080/members.

You can also run the generated tests.

./skinny db:migrate test
./skinny test

Now let’s create a war file for deployment to a Servlet container.

./skinny package

It’s also possible to build a standalone runnable jar file (with embedded Jetty server).

./skinny package:standalone

Try by using Yeoman generator


Yeoman

If you’re familiar with Yeoman, a generator for Skinny framework is available.

NPM

# brew install node
npm install -g yo
npm install -g generator-skinny
mkdir skinny-app
cd skinny-app
yo skinny
./skinny run

Integrating with existing Scalatra apps


Actually, an application built with Skinny framework is a normal Scalatra application.

After preparing the Scalatra app, just add the following dependency to your project/Build.scala.

libraryDependencies ++= Seq(
  "org.skinny-framework" %  "skinny-logback"            % "1.0.3",
  "org.skinny-framework" %% "skinny-assets"             % "1.3.8",
  "org.skinny-framework" %% "skinny-framework"          % "1.3.8",
  "org.skinny-framework" %% "skinny-task"               % "1.3.8",
  "org.skinny-framework" %% "skinny-scaldi"             % "1.3.8",
  "org.skinny-framework" %% "skinny-oauth2-controller"  % "1.3.8",
  "org.skinny-framework" %% "skinny-twitter-controller" % "1.3.8",
  "org.skinny-framework" %% "skinny-test"               % "1.3.8" % "test",
  "org.skinny-framework" %% "skinny-factory-girl"       % "1.3.8" % "test"
)

If you need only Skinny-ORM or Skinny-Validator, you can use only what you need. Even if you’re using Play2 (or any other framework), these components are available for you as well.

libraryDependencies ++= Seq(
  "org.skinny-framework" %  "skinny-logback"      % "1.0.3",
  "org.skinny-framework" %% "skinny-orm"          % "1.3.8",
  "org.skinny-framework" %% "skinny-mailer"       % "1.3.8",
  "org.skinny-framework" %% "skinny-standalone"   % "1.3.8",
  "org.skinny-framework" %% "skinny-validator"    % "1.3.8",
  "org.skinny-framework" %% "skinny-http-client"  % "1.3.8",
  "org.skinny-framework" %% "skinny-factory-girl" % "1.3.8" % "test"
)

1.3 Migration Guide for 1.2.x Users


https://github.com/skinny-framework/skinny-framework/releases/tag/1.3.0

Deprecated joda-time methods in WrappedResultSet are removed. If you you’re using rs.dateTime(...), just rename it to rs.jodaDateTime(...).


1.2 Migration Guide for 1.1.x Users


APIs are basically compatible. If you don’t have some extensions that depend on LocaleFeature, RequestScopeFeature and SkinnySessionFilter methods, your app will work fine without changing your code.

https://github.com/skinny-framework/skinny-framework/releases/tag/1.2.0

Though we believe migration is not difficult, please tell us here if you find something wrong.

https://github.com/skinny-framework/skinny-framework/issues


1.1 Migration Guide for 1.0.x Users


Skinny 1.1 APIs are basically compatible with Skinny 1.0 though the release includes basic dependencies’ major upgrades. If your app depends on the dependencies directly (not via Skinny APIs), you may need to update your code.

  • All the components run on Scala 2.11 or Scala 2.10 (Skinny 1.0: Scala 2.10)
  • Web framework runs on Java 7 or higher (Skinny 1.0: Java 6 or higher)
  • Web framework is compatible with Servlet API 3.1 (Skinny 1.0: Servlet 3.0)
  • Web framework depends on Scalatra 2.3 (Skinny 1.0: Scalatra 2.2)
  • ORM depends on ScalikeJDBC 2.0 (Skinny 1.0: ScalikeJDBC 1.8)
  • Migration command depends on Flyway 3.0 (Skinny 1.0: Flyway 2.3)
  • Test support depends on ScalaTest 2.2 (Skinny 1.0: ScalaTest 1.9)

https://github.com/skinny-framework/skinny-framework/releases/tag/1.1.0

Though we believe migration is not difficult, please tell us here if you find something wrong.

https://github.com/skinny-framework/skinny-framework/issues


Update skinny project structure by using Yeoman

Yo can use Yeoman to merge updates in skinny-blank-app project. Yeoman’s merging process is similar to Rails generator. Very easy to use!

npm install -g yo
npm install -g generator-skinny
yo skinny

“org.scalatest.matchers.ShouldMatchers” is deprecated

Use “org.scalatest.Matchers” instead. Sorry to say this.


Importing “scalikejdbc.SQLInterpolation._” is deprecated

Just import only “scalikejdbc._”.

See also: https://github.com/skinny-framework/skinny-framework/commit/1e44f60e5c5d0f53ab0102697a00413ad7a696d0


Renamed joda-time APIs due to JSR-310

WrappedResultSet#dateTime, #localDate, #localTime and #localDateTime are deprecated and #jodaDateTime and #jodaXXX are added.

See also the issue: https://github.com/scalikejdbc/scalikejdbc/issues/222

Other changes in ScalikeJDBC 2.0:

https://github.com/scalikejdbc/scalikejdbc/blob/develop/notes/2.0.0.markdown


skinny package’s Scalate precompilation error

Since Scalate 1.7.0, Skinny’s blank app project’s settings fail to execute package command.

default_ssp.scala:7: $_scalate_$default_ssp is already defined as object $_scalate_$default_ssp

Remove scalateSettings if your build settings loads it twice.

See also: https://github.com/skinny-framework/skinny-framework/commit/4ad2b874116ad3b60b76b104b2bf528106aeda87


Skinny’s Components Overview


Routing & Controller & Validator


Skinny’s routing mechanism and controller layer on MVC architecture can be thought of as a rich Scalatra. Skinny’s extension provides you much simpler/rich syntax. Of course, if you need to use Scalatra’s API directly, Skinny never bothers you.

Scalatra

SkinnyController is a trait which extends ScalatraFilter and includes various useful components out-of-the-box.

// src/main/scala/controller/MembersController.scala
class MembersController extends SkinnyController {
  def index = {
    set("members" -> Member.findAll()) // can call this in views
    render("/members/index")
  }
}
// src/main/scala/controller/Controllers.scala
object Controllers {
  object members extends MembersController with Routes {
    val indexUrl = get("/members/?")(index).as('index)
  }
}
// src/main/scala/ScalatraBootstrap.scala
class ScalatraBootstrap extends SkinnyLifeCycle {
  override def initSkinnyApp(ctx: ServletContext) {
    Controllers.members.mount(ctx)
  }
}

SkinnyResource, which is similar to Rails ActiveResource, is also available. It’s a pretty DRY way to define RESTful resources.

object CompaniesController extends SkinnyResource {
  protectFromForgery()

  override def model = Company
  override def resourcesName = "companies"
  override def resourceName = "company"

  ...
}

Company object should implement skinny.SkinnyModel APIs and you should prepare some view templates under src/main/webapp/WEB-INF/views/members/.

See in detail: Controller & Routes


Skinny ORM


Skinny provides you Skinny-ORM as the default O/R mapper, which is built with ScalikeJDBC.

Logo

Skinny-ORM does a lot of work under the hood, so you don’t need to write much code. Your first model class and companion are here.

case class Member(id: Long, name: String, createdAt: DateTime)

object Member extends SkinnyCRUDMapper[Member] {
  override def defaultAlias = createAlias("m")
  override def extract(rs: WrappedResultSet, n: ResultName[Member]) = new Member(
    id = rs.long(n.id),
    name = rs.string(n.name),
    createdAt = rs.dateTime(n.createdAt)
  )
}

That’s all! Now you can use the following APIs.

// find by primary key
val member: Option[Member] = Member.findById(123)
val member: Option[Member] = Member.where('id -> 123).apply().headOption
val members: List[Member] = Member.where('id -> Seq(123, 234, 345)).apply()

// find many
val members: List[Member] = Member.findAll()
val groupMembers = Member.where('groupName -> "Scala Users", 'deleted -> false).apply()

// create with unsafe parameters
Member.createWithAttributes(
  'id -> 123,
  'name -> "Chris",
  'createdAt -> DateTime.now
)
// update with unsafe parameters
Member.updateById(123).withAttributes('name -> "Alice")
// delete
Member.deleteById(234)

Skinny ORM is an independent library from Skinny environment. You can use it with Play.

Logo

Check our example app: https://github.com/skinny-framework/skinny-orm-in-play

See others in detail: O/R Mapper


DB Migration with Flyway


DB migration is provided by Flyway. Usage is pretty simple.

Flyway Logo

./skinny db:migrate [env]

This command expects src/main/resources/db/migration/V***__***.sql files.

See in detail: DB Migration


View Templates


Skinny framework basically follows Scalatra’s Scalate Support, but Skinny has an additional convention.

Scalate Logo

Template paths should be of the form {path}.{format}.{extension}. Expected {format} are html, json, js and xml.

For instance, assuming your controller code looks like this:

class MembersController extends SkinnyController {
  def index = {
    set("members", Member.findAll())
    render("/members/index")
  }
}

The render method expects that src/main/webapp/WEB-INF/views/members/index.html.ssp exists.

<%=@val members: Seq[model.Member] %>
<hr/>
#for (member <- members)
  ${member.name}
#end

Scalate supports many template engines. For example, if you want to write your template using Jade, save it as src/main/webapp/WEB-INF/views/members/index.html.jade instead.

See in detail: View Templates


Skinny Mailer


SkinnyMailer makes sending emails pretty easy.

val config = SkinnyMailerConfigdefault.copy(
  debug = true
)
val mailer = SkinnyMailer(config)

mailer
  .from("info@skinny-framework.org")
  .to("you@example.com")
  .cc("support@skinny-framework.org", "xxx@example.com")
  .subject("Skinny Framework 1.0.0 is out!")
  .body {
    """Hi all,
    |
    |We're very proud to announce that Skinny Framework version 1.0.0 is relaesed.
    |
    |.....
    |
    |Best,
    |Skinny Framework Team
    |""".stripMargin
  }.deliver()

See in detail: Mail


Assets Support (CoffeeScript, LESS, Sass, ReactJS, Scala.js)


CoffeeScript Logo LESS Logo Sass Logo React Logo Scala.js

First, add skinny-assets to libraryDependencies.

libraryDependencies ++= Seq(
  "org.skinny-framework" %% "skinny-framework" % "1.3.8",
  "org.skinny-framework" %% "skinny-assets"    % "1.3.8",
  "org.skinny-framework" %% "skinny-test"      % "1.3.8" % "test"
)

And then, add AssetsController to routes. Now you can easily use CoffeeScript, LESS and Sass.

// src/main/scala/ScalatraBootstrap.scala
class ScalatraBootstrap extends SkinnyLifeCycle {
  override def initSkinnyApp(ctx: ServletContext) {
    AssetsController.mount(ctx)
  }
}

AssetsController supports Last-Modified header and returns status 304 correctly if the requested file isn’t changed.

However, precompiling the assets is highly recommended in production (./skinny package does that).

See in detail: Assets Support


Angular.js Friendly Server Side


Angular Logo

By using AngularXHRServerFeature trait, your controllers will be Angular.js friendly JSON API provider.

class ArticlesController extends SkinnyApiResource with AngularXHRServerFeature {
  // Enable Angular's XSRF protection
  protectFromForgery()

  // JSON request body will be merged into Scalatra params automatically
  // ...

}

And your ngResource is like this:

app.factory('Article', ['$resource', function($resource) {
  return $resource('/api/articles/:id.json', {}, {});
}]);

See in detail: Angular Support


Testing Support


You can use Scalatra’s great test support. Some extra optional features are provided by the skinny-test library.

class ControllerSpec extends ScalatraFlatSpec with SkinnyTestSupport {
  addFilter(MembersController, "/*")

  it should "show index page" in {
    withSession("userId" -> "Alice") {
      get("/members") { status should equal(200) }
    }
  }
}

See in detail: Testing


FactoryGirl


Though Skinny’s FactoryGirl is not a complete port of thoughtbot/factory_girl, this module will be quite useful when testing your apps.

case class Company(id: Long, name: String)
object Company extends SkinnyCRUDMapper[Company] {
  def extract ...
}

val company1 = FactoryGirl(Company).create()

Configuration is not in yaml files but a typesafe-config conf file. In this example, src/test/resources/factories.conf looks like this:

company {
  name="Typesafe"
}

See in detail: FactoryGirl


Skinny Framework Team and You


Skinny Framework team is passionately working on this project.

https://github.com/orgs/skinny-framework/people

If you’re interested in Skinny development, pull requests are always welcome.

How to contribute


Build Status


Build Status


Under The MIT License


(The MIT License)

Copyright © skinny-framework.org


If you find a typo or mistake in this page, please report or fix it. How?