Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Web Development with Julia and Genie
Web Development with Julia and Genie

Web Development with Julia and Genie: A hands-on guide to high-performance server-side web development with the Julia programming language

eBook
€17.99 €25.99
Paperback
€31.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Table of content icon View table of contents Preview book icon Preview Book

Web Development with Julia and Genie

Julia Programming Overview

Julia is a high-performance, open source computing language, mostly applied to data analysis, machine learning, and other scientific and technical computing applications.

The language combines the ease of use of Python or R with the speed of C and eliminates the need for using two languages to develop data intensive applications. It is as readable and high-level as Python and because of its type inference and optional typing, behaves as a dynamic language. It is also as fast as C, but much more readable. As a new programming language, Julia borrowed some of the best features from other modern languages. For example, like Ruby, it doesn’t use semicolons or curly braces for delimiting code; instead, it uses a more Pascal-like syntax, with end to indicate where a code structure stops.

Julia is not a classic object-oriented language like Java; instead, it is more function-oriented, but it also has a struct data type like C. Functions that act on and transform data are the basic building blocks. The language also has built-in parallel computing capabilities and can scale up very easily.

Julia also provides an extensive standard library from the start. The language’s usage and popularity are steadily rising; it has been downloaded by users from more than 10,000 companies and is used at over 1,500 universities worldwide (https://juliacomputing.com/media/2022/02/julia-turns-ten-years-old/).

This chapter will touch on the main Julia concepts we will need in web development including types, flow control, functions, packages, and modules. We will introduce some examples relating to the ToDo app project theme for Part 2 of this book.

We’ll also show code snippets from the Genie framework that are used in Part 2. We wrap up with a section on how Julia works internally, which makes us better understand Julia’s efficacy in web development. By the end of this chapter, your Julia knowledge will be refreshed, and you’ll be much better prepared to grasp the rest of the book.

In this chapter, we will cover the following topics:

  • Working with Julia
  • Types, flow controls, and functions in Julia
  • Useful techniques in Julia web development
  • Using Julia modules and packages
  • How Julia works
  • Why Julia is a good fit for web development

Technical requirements

To follow through with all the exercises in this chapter and the rest of the book, you will need the following:

All the code examples in this book have been run on a Windows machine. You may find subtle differences in output if you are using Linux/macOS. Where necessary, command variations for both machines have been specified.

The complete source code for this chapter can be found at https://github.com/PacktPublishing/Web-Development-with-Julia-and-Genie/tree/main/Chapter1.

Working with Julia

In this section, we will set up a standard Julia development environment, and learn how to work with Julia scripts as well as the Read–Eval–Print Loop (REPL). The REPL allows you to work with Julia in an interactive way, trying out expressions, function calls, and even executing whole programs.

You’re good to go when typing in julia at the terminal starts up the REPL:

Figure 1.1 – The Julia REPL

Figure 1.1 – The Julia REPL

Using the REPL to use Julia interactively

Try typing in 256^2, giving the result 65536, or rand(), which gives you a random number between 0 and 1, for example, 0.02925477322848513. We’ll use the REPL extensively throughout the book, and the Genie web framework discussed in Part 2 allows you to build your entire web app from the REPL.

Some useful REPL keyboard shortcuts you will use often include the following:

  • Ctrl + D: To exit the REPL
  • Ctrl + L: To clear the screen
  • Ctrl + C: To get a new prompt
  • Up and down arrows: To reuse recent commands

To see which folder you are in, type pwd(). To change the current folder, execute cd("path/to/folder").

A feature we’ll use a lot in Genie is creating new files from within the REPL with the touch command. For example, to create an empty testset.jl file in an existing folder structure, testing/phase1, enter the following:

julia> touch(joinpath("testing", "phase1", "testset.jl"))

The REPL returns testing\\phase1\\testset.jl on Windows and testing/phase1/testset.jl on *nix systems.

The joinpath function constructs the directory path starting in the current folder, and touch creates the file.

Using the package mode to jump-start a project

The Julia ecosystem encompasses thousands of libraries, called packages (see https://julialang.org/packages/), for which Julia has a built-in package manager, Pkg.

The REPL has a special mode for working with packages, which is started by typing ] at julia> prompt, which brings you to package mode: (@v1.8) pkg>.

Some useful commands in this mode to type in after the pkg> prompt are as follows:

  • st or status: Gets a list of all the packages installed in your environment.
  • add PackageName: Adds a new package (you can add several packages separated by , if needed).
  • up or update: Updates all your packages.
  • up or update PackageName: Updates a specific package.
  • activate .: Activates the current project environment (see the Packages and projects section under Using Julia modules and packages). rm or remove PackageName: Removes a specific package.
  • ?: Lists all available commands.
  • The backspace key: Exits the pkg> mode.

In the next section, Parsing a CSV file, we will work with a comma-separated values (CSV) file of to-do items. The CSV package can be imported and set up to be used in your Julia REPL by typing the following:

julia> using Pkg
julia> Pkg.add("CSV")
julia> using CSV

The last line of the preceding command brings the definitions of the CSV package into scope.

Alternatively, from the package mode, use the following:

]:
(@v1.8) pkg> add CSV

The preceding command installs all packages CSV depends on and then precompiles them. This way, the project gets a jump-start, because the just-in-time (JIT) compiler doesn’t have to do this work anymore.

Using Julia with the VS Code plugin

Julia code can also be saved and edited in files with a .jl extension. Numerous IDEs exist to do that. In this book, we’ll use the VS Code platform with the excellent Julia plugin, which provides syntax highlighting and completion, lookup definitions, and plotting among many other features.

A handy way to start VS Code from the terminal prompt is by typing in code.

Search in the Extensions tab for Julia and install it. Then, open up a new file, and type in println("Hi Web World from Julia!"), and save it as hiweb.jl.

Run the program in VS Code with F5 to see the string printed out. Or start the REPL and type the following to get the same result:

julia> include("hiweb.jl")

include evaluates the contents of the input source file.

Or, from a terminal prompt, execute a Julia source file simply by typing the following:

julia hiweb.jl

In all cases, the output will be Hi Web World from Julia!

The include command loads in the Julia file and executes the code.

Continuing the example from the previous section, if you want to start editing the newly created testset.jl file in VS Code when you are working in the REPL, simply type the following:

 julia> edit(joinpath("testing", "phase1", "testset.jl"))

Now that you have some idea of working with Julia using the REPL, in package mode, and using VS Code, let us dig deeper into understanding the basics of the language. In the next section, we will explore some of the basic types, flow controls, functions, and methods in Julia.

Types, flow controls, and functions in Julia

In this section, we will discuss some basic concepts in Julia and start applying them to our ToDo project. Let us start by understanding the types of data that can be used in Julia.

Types

To achieve its high level of performance, Julia needs to know the types of data it will handle at either compile time or runtime. You can annotate a local function variable x with a type Int16 explicitly, like in x::Int16 = 42.

But you can just as well write x = 42. If you then ask for the variable’s type with typeof(x), you get Int64 (or Int32 on 32-bit operating systems). So, you see, there is a difference: if you know Int16 is sufficient, you can save memory here, which can be important if there are many such cases.

Explicit typing is sometimes done for function arguments and can enhance performance. Types can also be added at a later stage of the project. Also, although Julia allows it, do not change a variable’s type: this is very bad for performance. To test whether a variable is of a certain type, use the isa function: isa(x, Int64) returns true.

Julia has an abundance of built-in types, ranging from Char, Bool, Int8 to Int128 (and its unsigned counterparts, UInt8 and so on), Float16 to Float64, String, Array, Dict, and Set.

Strings containing variables or expressions can be constructed by string interpolation: when x has the value 108, the string "The value of x is $x" is evaluated to "The value of x is 108". An expression must be placed within parentheses, like "6 * 2 is $(6 * 2)", which evaluates to "6 * 2 is 12".

It is best practice not to use global variables as they cause bugs and have major performance issues. It is better to use constants, such as const var1 = 3, which can’t be modified. In this case, Julia’s JIT compiler can generate much more efficient code.

As an alternative to global variables, you can use Refs as is done in the Genie framework, like this:

const var = Ref{Float64}(0.0)
var[] = 20.0

That way, you make certain that the type of var will not change.

Types follow a hierarchy, with the Any type at the top, which, as the name says, allows any type for such a variable. In Figure 1.2, we show a part of this type tree:

Figure 1.2 – Part of Julia’s type hierarchy [Adapted from Type-hierarchy-for-julia-numbers.png made available at https://commons.wikimedia.org/wiki/File:Type-hierarchy-for-julia-numbers.png by Cormullion, licensed under the CC BY-SA 4.0 license (https://creativecommons.org/licenses/by-sa/4.0/deed.en)]

Figure 1.2 – Part of Julia’s type hierarchy [Adapted from Type-hierarchy-for-julia-numbers.png made available at https://commons.wikimedia.org/wiki/File:Type-hierarchy-for-julia-numbers.png by Cormullion, licensed under the CC BY-SA 4.0 license (https://creativecommons.org/licenses/by-sa/4.0/deed.en)]

In the preceding figure, we see that the Integer type has subtypes Unsigned, Signed, and Bool.

A subtype (a kind of inheritance relationship) is indicated in code as follows:

Bool <: Integer

Types with subtypes are abstract types; we cannot create an instance of this type. The types that have no subtypes (the leaf nodes) are concrete types; only these can have data. For example, Bool variables can have the values true and false. A variable b declared as Integer has in fact the type Int64:

b :: Integer = 42
typeof(b)   # => Int64

To describe a ToDo-item, we need several data items or fields. Let us have a look at what types of values each field can take using some examples:

  • id: Here, we could add an integer of type Int32, such as 1.
  • description: Here, we can only use a String, such as "Getting groceries".
  • completed: This field will take a Bool value, which is initially set to false.
  • created: This field takes the Date type. This type lives in the Dates module, so to make it known to Julia, we have to say so in code: using Dates.
  • priority: This field could take an integer between 1 to 10.

We could group all this data into an array-like type, called a Vector. Because we have all kinds of items of different types, the type of the items is Any. So, our Vector would look as follows:

julia> todo1 = [1, "Getting groceries", false, Date("2022-04-01", "yyyy-mm-dd"), 5]

Running the preceding code would give us the following output:

5-element Vector{Any}:
1
"Getting groceries"
false
2022-04-01
5

To get the description, we have to use an index, todo1[2]; the index is 2 because Julia array indices start from 1.

A better way to group the data is using a struct:

julia> mutable struct ToDo
                id::Int32
                description::String
                completed::Bool
                created::Date
                priority::Int8
       end

Then, we can define the same todo item as in the preceding code as a struct instance:

julia> todo1 = ToDo(1, "Getting groceries", false, Date("2022-04-01", "yyyy-mm-dd"), 5)

Now, instead of using an index, we can directly ask for a particular field, for example, the todo’s description:

julia> todo1.description
"Getting groceries"

Or we can indicate when the item is dealt with:

julia> todo1.completed = true

To nicely print out the data of a struct, use the show (struct) or display (struct) functions.

Another thing that we will see used a lot in Genie is symbols. These are names or expressions prefixed by a colon, for example, :customer. Symbols are immutable and hashed by the language for fast comparison. A symbol is used to represent a variable in metaprogramming.

The : quote operator prevents Julia from evaluating the code of the expression. Instead, that code will be evaluated when the expression is passed to eval at runtime. The following code snippet shows this behavior:

ex = :(a + b * c + 1)
a = 1
b = 2
c = 3
println("ex is $ex")  # => ex is a + b * c + 1
println("ex is $( eval(ex) )")  # => ex is 8

See the Useful techniques in Julia web development section for how symbols can be used.

In this section, we have seen that the use of the appropriate types is very important in Julia: it can make your code more performant and readable.

Flow controls

Julia is equipped with all the standard flow controls, including the following:

  • if elseif else end: Branching on a condition.
  • for in end: Looping with a counter or iterating over a set of values.
  • while end: Looping while testing on a condition.
  • break: Used to jump out of a loop.
  • continue: Used to continue with the loop’s next iteration.
  • throw: Used to throw exceptions and use code that can go wrong in a try construct. Here is an example:
    try
    # dangerous code
    catch ex # handle possible exceptions
    finally  # clean up resources
    end

You can see a concrete usage example of try/catch in the echo server example in the Making a TCP echo server with TCP-IP Sockets section of Chapter 2, Using Julia Standard Web Packages. However, don’t overuse this feature; it can degrade performance (for those curious, this is because the runtime needs to add the stack trace to the exception, and afterward, needs to unwind it).

  • You can also make your own custom exceptions like this:
    mutable struct CustomException <: Exception
    # fields
    end

Let’s see an example of flow control in action. Here is how we compare the priorities of todos:

if todo2.priority > todo1.priority
    println("Better do todo2 first")
else
    println("Better do todo1 first")
end

So, you see, Julia has all the basic flow controls like any standard programming language.

Functions and methods

Functions are the basic tools in Julia. They are defined as follows:

function name(params)
 # body code
end

Alternatively, we can use a one-liner:

name(params) = # body code

Functions are very powerful in Julia. They support optional arguments (which provide default values when no value is provided) and keyword arguments (here the argument’s arg1 value must be specified as func(arg1=value) when the function is called). Functions can be nested inside other functions, passed as a parameter to a function, and returned as a value from a function. Neither argument types nor return types are required, but they can be specified using the :: notation.

Values are not copied when they are passed to functions; instead, the arguments are new variable bindings for these values.

To better indicate that a function changes its argument, append ! to its name, for example:

julia> increase_priority!(todo) = todo.priority += 1
julia> todo1.priority
5
julia> increase_priority!(todo1)
6
julia> todo1.priority
6

In the preceding code, notice that we don’t need to indicate the type of the argument; todo functions are by default generic, meaning that in principle, they can take any type. The JIT compiler will generate a different compiled version of the function each time it is called with arguments of a new type. A concrete version of a function for a specific combination of argument types is called a method in Julia. You can define different methods of a function (also called function overloading) by using a different number of arguments or arguments with different types with the same function name.

For example, here are two overloading methods for a move function:

abstract type Vehicle end
function move(v::Vehicle, dist::Float64)
  println("Moving by $dist meters")
end
function move(v::Vehicle, dist::LightYears)
  println("Blazing across $dist light years")
end

The Julia runtime stores a list of all the methods in a virtual method table (vtable) on the function itself. Methods in Julia belong to a function, and not to a particular type as in object-oriented languages.

In practice, however, an error will be generated when the function cannot be applied for the supplied type. An example of such an error is as follows:

julia> increase_priority!("does this work?")

If you run the preceding code, you will get the following output:

ERROR: type String has no field priority

One could say that a function belongs to multiple types, or that a function is specialized or overloaded for different combinations of types. This key feature of Julia is called multiple dispatch, meaning that the execution can be dispatched on multiple argument types. Julia’s ability to compile code that reads like a high-level dynamic language into machine code that performs like C almost entirely derives from this ability, which neither Python, C++, nor Fortran implement.

A function can also take a variable number of arguments, indicated by three dots (…, called the splat operator). For example, the validate function takes two arguments, a and b, and then a variable number of values (args…):

validate(a, b, args…)

The function can be called as validate(1, 2, 3, 4, 5), or as validate(1, 2, 3), or even validate(1, 2). The type of args… is Vararg; it can be type annotated as args::Vararg{Any}.

If you see what seems to be a function call prefixed with an @ (such as @error or @authenticated! in Genie), you are looking at a macro call. A macro is code that is modified and expanded at parse-time, so before the code is actually compiled. For example, @show is a macro that displays the expression to be evaluated and its result, and then returns the value of the result. You can see examples in action with @async in the Making a TCP echo server with TCP-IP Sockets section in Chapter 2, Using Julia Standard Web Packages.

In this section, we saw that Julia has pretty much what you expect in any modern programming language: a complete type system, normal flow controls, exception handling, and versatile functions. We cannot review all the methods that Julia has to offer in this book, but detailed information regarding methods can be found in the Julia documentation: https://docs.julialang.org/en/v1/.

Now that you know some basic features that define the Julia language, let us explore some useful techniques that can help us further to take advantage of the speed of Julia.

Useful techniques in Julia web development

In this section, we will highlight some methods and techniques that you will see used often in Julia web development and that we will also use in the project in Part 2. Here is a list of these key techniques:

  • Multi-line strings: These strings are delineated with """. These are often useful in web apps to use chunks of HTML code in a variable as follows:
    form = """ <form action="/" method="POST" enctype="multipart/form-data"> <input type="text" name="name" value="" placeholder="What's your name?" /> <input type="submit" value="Greet" /> </form> """
  • String substitution: This can be used to insert variable contents into messages on the screen as follows:
    <h4 class="container">
    Sorry, no results were found for "$(params(:search_movies))"
    </h4>
  • do block syntax: This syntax makes the code easier to read. Here is a simple example:
    list = [1, 2, 3]
    map(x -> x^2, list)

This can also be written as follows:

map(list) -> do x
    x^2
end
  • Here is an example usage from the Genie framework:
    route("/hello.html") do
     html("Hello World")
    end

Here, route() and html() are functions from the Genie framework. The do x syntax creates an anonymous function with argument x and passes it as the first argument to the function stated before do. In this example, the string "Hello World" will be shown on the web page when the /hello.html URL is requested.

Another way to write this, which is clearly not that readable, is as follows:

route(html("Hello World"), "/hello.html")

We will be using this do syntax quite often in Part 2.

  • &&: The Boolean and && operator is often used to write concise conditional code, for example:
    isempty(strip(params(:search_movies)))
    && redirect(:get_movies)

The preceding code first evaluates the isempty(strip(params(:search_movies))) part; if this is false, nothing happens anymore. Only if the first part is true will the second, redirect(:get_movies), get evaluated. Thus, if the search_movies parameter has a value, only then will the redirect to :get_movies take place.

  • ||: The or || operator doesn’t evaluate the part after || when the first part is true, for example:
    isa(getfield(m, field), Int) || return ValidationResult(invalid, :is_int, "should be an int")

In the preceding example, if m is of type Int, the ValidationResult from the right-hand side is not shown.

  • Pipe operator: This operator, denoted by |>, is quite handy. An example is as follows:
    h1("Welcome Admin") |> html

The output of the preceding function before the pipe operator (|>) is given as a first argument to the function after the pipe. This allows for easy function chaining.

  • Ternary form: An if condition a else b end statement is often written in a ternary form: condition ? a : b.

An example is as follows:

flash_has_message() ? """<div class="alert alert-$flashtype alert-dismissable">$(flash())</div>""" : ""

If the function flash_has_message() returns true, then the multiline string after ? (which contains the HTML code for a div) is the result of the expression; if false the empty string "" is returned.

  • Symbols: These are often used in Julia (web) code denoted by :, for example:
    julia> sym = :info
    :info
    julia> typeof(sym)
    Symbol

Symbols are used to indicate access to a variable (such as info), but what info exactly contains is not evaluated at that moment in code. A symbol gets replaced with the value bound to that symbol when the expression containing the symbol is evaluated at runtime.

Here is an example from Genie passing the values of the:user_id and :user_status variables in the payload to a createUser function:

createUser(postpayload(:user_id), postpayload(:user_status, "active"))

So, postpayload(:user_id) can be seen as binding values to variables (something that can change) inside user-provided expressions. Here, on evaluation, :user_id is replaced by the value Symbol is pointing to.

  • <% %>: Web frameworks often embed code inside HTML with <% %>. This can be used in the Julia Genie web framework, as follows:
    <h4><% movie.description %></h4>

In the preceding code, <% %> is used to insert a description field of a movie instance in that place.

<% %> can also contain whole blocks of code as well as function calls.

Embedded code can also contain a call to the @yield macro, like in the following snippet from app.jl.html in Genie:

<body>
<div class="container">
<%
@yield
%>
</div>
</body>

@yield is used to output the content of the view/controller into the layout.

Do familiarize yourself with the techniques described in this section. Doing so will make Julia web code instantly more understandable. All Julia web apps are projects that contain modules and use packages, so that’s what we’ll discuss in the next section.

Using Julia modules and packages

Code in Julia is not limited to functions and can be organized at higher levels through modules and packages. A module is one level higher than functions under which code in Julia can be organized. A package is another level higher, can contain one or more modules, and provides functionality that can be reused by other Julia projects. Often, a web app is a package, containing a number of modules. When the package contains a project file called Project.toml, the file is also a project.

Modules

Modules are used to group together the definitions of types, functions, constants, and so on that are related. By convention, a file named M.jl will always define a module named M.

Such a module will be declared as follows (shown here for the Genie framework):

module Genie
# Loads dependencies and bootstraps a Genie app.
# Exposes core Genie functionality.
end

And it will be stored in Genie.jl.

To illustrate, let’s create a module ToDoApp inside a ToDoApp.jl file, with the ToDo struct definition and a display function (see Chapter1\modules\ToDoApp.jl in the code repository):

module ToDoApp
using Dates   # to make the Date type available
export print_todo, ToDo
mutable struct ToDo
  id::Int32
  description::String
  completed::Bool
  created::Date
  priority::Int8
end
function print_todo(todo)
  if !todo.completed
    println("I still have to do: $(todo.description)")
    print("A todo created at: ")
    helper(todo)
  end
end
function helper(todo)
   println(todo.created)
end
end

In the preceding code, we see that using is needed to bring in the definitions of the Dates module.

In the REPL, we evaluate the preceding Julia script with include(" ToDoApp.jl"). Then, we employ using .ToDoApp.

The period (.) is used here because we want to look for definitions inside the scope of the current module. Without this, we get an error:

julia> using ToDoApp
ERROR: ArgumentError: Package ToDoApp not found in current path
Import

Also, we must do using Dates so that the Date type is recognized, which is needed when making a ToDo instance:

Now, let us define our struct instance as follows:

julia> todo1 = ToDo(1, "Getting groceries", false, Date("2022-04-01", "yyyy-mm-dd"), 5)
Main.ToDoApp.ToDo(1, "Getting groceries", false, Date("2022-04-01"), 5)

We can now call the exported print_todo function:

julia> print_todo(todo1)
I still have to do: Getting groceries
A todo created at: 2022-04-01

However, the helper function is not available because it was not exported from the module:

julia> helper(todo1)
ERROR: UndefVarError: helper not defined

But we can call the helper function as follows:

ToDoApp.helper(todo1) # => 2022-04-01

When evaluating using, Julia looks in the filesystem for modules or packages in paths that are stored in the LOAD_PATH variable. By default, LOAD_PATH contains the following:

julia> LOAD_PATH
3-element Vector{String}:
"@"
"@v#.#"
"@stdlib"

The preceding code implies that first the current project is searched, then the default Julia environment, and then the standard library.

The variable @__DIR__ contains the current folder. So, another way to enable Julia to search for modules or packages in the current folder is to say push!(LOAD_PATH, @__DIR__).

Let us summarize when and how to use using:

  • using MyPackage looks in the LOAD_PATH for a file called MyPackage.jl and loads the module contained in that file; all exported definitions are loaded into the current scope
  • using .MyPackage: This part of the code instructs looking for definitions inside the scope of the current module, which is needed because we have previously done include ("MyPackage.jl")
  • using ..MyPackage: This part of the code instructs looking for definitions inside the parent scope of the current module

Besides include and using, we can also bring in a module with import. Then, you have to prefix the name of a function or another object with its module name when it is used. For example, after import Inflector has imported the Inflector module, you have to use its to_plural function, as Inflector.to_plural(name).

The import keyword also has to be used when you want to extend functions with new methods. For example, if you want to pretty-print your own types with a new version of the show function, you first have to do import Base.show.

To bring in specific definitions, use : after using or import as follows:

import SearchLight: AbstractModel

As an example, here are the starting lines of the Genie module:

module Genie
import Inflector
include("Configuration.jl")
using .Configuration
const config = Configuration.Settings()
include("constants.jl")
import Sockets
import Logging
using Reexport
Using Revise
# rest of the code
end

Packages and projects

Packages are managed using the Git version control system and the package manager, Pkg (which is itself a package!). They are stored on GitHub, and each Julia package is named with a .jl suffix. A single GitHub repository may host one or more packages, but a good convention is one repository containing just one package.

A single package with the name P will always contain a P.jl file. By convention, this is placed in a subfolder, src. You can’t have other top-level modules in a single package.

As an example, the Genie framework, called Genie.jl, can be found at https://github.com/GenieFramework/Genie.jl.

A project is a package that contains two .toml files, which declare the packages your project depends on. You can create a project from the REPL as follows:

(@v1.8) pkg> generate MyPackage
Generating project MyPackage:
MyPackage\Project.toml
MyPackage\src/MyPackage.jl

The output will show the file structure created by the generate command.

The default Project.toml file contains the following:

name = "MyPackage"
uuid = "607adcac-db05-4b5b-9d7e-b11c396083d4"
authors = ["YourName<email-address>"]
version = "0.1.0"

A project can also contain a [deps] section, containing the names and universally unique ids (UUID) of the packages your project depends on (we will see an example of this in the next section). When adding a package to your project with the add command, the entry in the [deps] section is automatically filled in. The [compat] section constraints compatibility for the dependencies listed under [deps].

Besides Project.toml, a project can also have a manifest in the form of a Manifest.toml file, as indeed all Genie projects have. This file is generated and maintained by Pkg and, in general, should never be modified manually. The Manifest.toml file records the state of the packages in the current project environment, including exact information about (direct and indirect) dependencies of the project.

Given these two files, you can exactly reproduce the package dependency environment of a project, so this guarantees reproducibility.

Parsing a CSV file

As a simple example of how to work with packages, let’s read the data from a CSV file and display it. Suppose we have a todos.csv file that contains a header line with column names, and then line by line, the field data of our to-dos, as follows:

id, description, completed, created, priority
1, "Getting groceries", true, "2022-04-01", 5
2, "Visiting my therapist", false, "2022-04-02", 4
3, "Getting a haircut", true, "2022-03-28", 6
4, "Paying the energy bill", false, "2022-04-04", 8
5, "Blog on workspace management", true, "2022-03-29", 4
6, "Book a flight to Israel", false, "2022-04-04", 3
7, "Conquer the world", true, "2022-03-29", 1

Start up a REPL to work with the data. We already installed the CSV package previously in the Using the package mode to jump-start a project section. We’ll also need the DataFrames package to show our data as a table with columns, so go into pkg mode by typing ] and give the command: add DataFrames.

Going back to the normal REPL, type the following using command:

using CSV, DataFrames

Now, we can read in the CSV file into a DataFrame object, df, with the following command:

df = CSV.read("todos.csv", DataFrame)

You will get the following output in the REPL:

Figure 1.3 – Viewing a CSV file in a DataFrame

Figure 1.3 – Viewing a CSV file in a DataFrame

If the file has no header line, specify the header=false keyword argument. Also, if the data delimiter is something different, such as ;, you can specify this with delim=';'.

The CSV package has a lot more capabilities for reading and writing, which you can learn about here: https://csv.juliadata.org/stable/index.html.

Now that you’ve seen how to use modules, packages, and projects, let’s examine Julia’s internal workings a bit more.

How Julia works

After this whirlwind tour of Julia, we want to see why Julia is a good fit for the web world. To do that, we must have a good understanding of Julia’s internal workings.

The Julia JIT compiler works at runtime, starting from the Julia source code. Note that code from packages is most often precompiled. Type, method, and module definitions are written in an efficient serialized form so that the JIT can start compiling much faster. The first time a function is called with a certain combination of types of arguments, the correct machine code for those types is generated through LLVM. Moreover, the machine code is cached from then on, so after the initial compilation stage, the optimized code is looked up in the function’s vtable (see Types, flow controls, and functions), and you get the bonus of much-improved performance.

Julia apps will often be long-running processes, so there needs to be a mechanism for freeing memory resources. The Julia developer, however, is not burdened with this task. Julia has a garbage collector process. This is a simple mark-and-sweep GC causing low overhead. The best advice here is as follows:

  • Avoid unnecessary memory allocations
  • Use standard-library methods that modify variables (whose name ends with !, for example, sort!) instead of creating new ones
  • Use immutable objects (const and struct)
  • Pre-allocate enough memory from the start to avoid GC altogether

Now that we know somewhat better how Julia works, we can argue why Julia can be used for web development.

Why Julia is a good fit for web development

Web development using Julia is very popular because of the following:

  • The app needs to be deployed only on the server, not on an unknown number of clients, so the effort to put an application into production is minimal. This is true for all backend programming languages. To execute the app, you have the choice between installing a Julia runtime on your server or building a standalone executable with PackageCompiler.jl.
  • Powerful web frameworks exist. This is certainly the case for main-stream dynamic languages, for example, Ruby on Rails, Django (a Python framework), or Phoenix (an Elixir framework). But Julia also saw the development of powerful web frameworks in recent years (we will discuss this more in Part 2), especially the Genie framework.
  • Data scientists want to show the results of their research online in a visual and interactive fashion. Here, Julia, being a scientific and technical computing language, really shines.

Let’s look at some important app properties and evaluate how Julia performs at these so that it becomes clear why Julia is a nice fit for web backend development and for exposing web services:

  • Speed: Response speed is always of the utmost importance, no matter the kind of app you’re running. Commonly used programming languages to develop web applications, such as PHP, Ruby, and Python, are interpreted languages. Typically, they are compiled to bytecode, which is deployed to a production machine where it is run on a virtual machine (VM). This VM translates the bytecode to machine code. This causes apps written in these languages to fall behind in certain benchmarks, so performance can be an issue.

Julia on the other hand is known for its excellent execution speed, because of its JIT compiler and highly optimized machine code generated through LLVM. That’s why Julia often stays within the 2x range from optimized C code while outperforming dynamic languages with orders of magnitude (see https://julialang.org/benchmarks/ and https://benchmarksgame-team.pages.debian.net/benchmarksgame/fastest/julia-python3.html).

Because of the JIT compiling stage, the startup of an application takes some time, which is sometimes called the JIT latency. So, often, the first execution of Julia code will take longer because execution waits for the compilation process. While this would be a problem for games or real-time apps, it is not an issue when developing web backends, which is a typically long-running process. Also, you can add a startup phase in which all your important code gets precompiled before exposing the app to users.

  • Garbage collection: The freeing of memory through the GC will be less noticeable on a server. Its effect is spread out over all client processes. See the previous How Julia works section, for some advice here.
  • Scalability: If your web app has an ever-growing number of users, you’ll likely run into problems sooner or later. Julia is designed for concurrent/parallel and distributed execution, which makes it highly scalable and thus particularly suited for running massive apps with many users. If your web application requires heavy calculations or can come under a heavy load, Julia will make a great difference.
  • Platforms: Because LLVM is used under the hood, Julia runs on very diverse platforms (see https://julialang.org/downloads/#currently_supported_platforms).
  • Functional: Julia’s emphasis on functions makes Julia a good choice for developing web services, which are typically function-oriented.

An ecosystem of libraries: Another of Julia’s advantages over competing languages is that libraries can be combined and extended very easily. This allows for more code reuse, which means less time and effort is needed in Julia to develop a web app as in the competing language frameworks. Moreover, all Python libraries can be used via PyCall.jl, so in case no existing Julia package meets your need, you can use an appropriate Python library. The same goes for R with Rcall.jl, and Java/Scala with JavaCall.jl. Also, Julia can call C code directly, without any libraries needed.

We can conclude that Julia’s performance and scalability characteristics and its extensive number of packages for visualizing data make it an excellent fit for the development of web apps, web services, and web dashboards.

Summary

In this chapter, we reviewed the Julia programming language in order to prepare ourselves for web development with Julia.

We worked with Julia in the REPL and with the VS Code editor, which is how we’ll build web apps in the rest of the book. Then, we looked at types, flow controls, functions, and methods, which you’ll need in any Julia app.

We followed that up with some useful Julia techniques in web development. We discussed modules and packages and illustrated them using the CSV and DataFrames packages.

Finally, we covered how the Julia runtime works and why Julia is a good fit for web development.

By now, you should be able to understand the underlying mechanisms of the code in future chapters and how to use Julia in your own projects.

In the next chapter, we’ll dive into what Julia’s standard library and JuliaWeb have to offer for building web apps.

Further reading

If you need a more thorough introduction or more details, follow a tutorial on https://julialang.org/learning/tutorials/, visit the Julia documentation at https://docs.julialang.org/en/v1/, or choose a book from https://julialang.org/learning/books/.

Left arrow icon Right arrow icon
Download code icon Download Code

Key benefits

  • A tutorial on web development from Julia expert, Ivo Balbaert and the creator of the Genie framework, Adrian Salceanu
  • A step-by-step approach to building a complete web app with the Genie framework
  • Develop secure and fast web apps using server-side development on Julia

Description

Julia’s high-performance and scalability characteristics and its extensive number of packages for visualizing data make it an excellent fit for developing web apps, web services, and web dashboards. The two parts of this book provide complete coverage to build your skills in web development. First, you'll refresh your knowledge of the main concepts in Julia that will further be used in web development. Then, you’ll use Julia’s standard web packages and examine how the building blocks of the web such as TCP-IP, web sockets, HTTP protocol, and so on are implemented in Julia’s standard library. Each topic is discussed and developed into code that you can apply in new projects, from static websites to dashboards. You’ll also understand how to choose the right Julia framework for a project. The second part of the book talks about the Genie framework. You’ll learn how to build a traditional to do app following the MVC design pattern. Next, you’ll add a REST API to this project, including testing and documentation. Later, you’ll explore the various ways of deploying an app in production, including authentication functionality. Finally, you’ll work on an interactive data dashboard, making various chart types and filters. By the end of this book, you’ll be able to build interactive web solutions on a large scale with a Julia-based web framework.

Who is this book for?

This book is for beginner to intermediate-level Julia programmers who want to enhance their skills in designing and developing large-scale web applications. The book helps you adopt Genie without any prior experience with the framework. Julia programming experience and a beginner-level understanding of web development concepts are required.

What you will learn

  • Understand how to make a web server with HTTP.jl and work with JSON data over the web
  • Discover how to build a static website with the Franklin framework
  • Explore Julia web development frameworks and work with them
  • Uncover the Julia infrastructure for development, testing, package management, and deployment
  • Develop an MVC web app with the Genie framework
  • Understand how to add a REST API to a web app
  • Create an interactive data dashboard with charts and filters
  • Test, document, and deploy maintainable web applications using Julia

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Nov 29, 2022
Length: 254 pages
Edition : 1st
Language : English
ISBN-13 : 9781801810951
Languages :
Tools :

What do you get with eBook?

Product feature icon Instant access to your Digital eBook purchase
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning

Product Details

Publication date : Nov 29, 2022
Length: 254 pages
Edition : 1st
Language : English
ISBN-13 : 9781801810951
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 100.97
Web Development with Julia and Genie
€31.99
Hands-On Design Patterns and Best Practices with Julia
€32.99
Interactive Visualization and Plotting with Julia
€35.99
Total 100.97 Stars icon

Table of Contents

12 Chapters
Part 1: Developing Web Apps with Julia Chevron down icon Chevron up icon
Chapter 1: Julia Programming Overview Chevron down icon Chevron up icon
Chapter 2: Using Julia Standard Web Packages Chevron down icon Chevron up icon
Chapter 3: Applying Julia in Various Use Cases on the Web Chevron down icon Chevron up icon
Part 2: Using the Genie Rapid Web Development Framework Chevron down icon Chevron up icon
Chapter 4: Building an MVC ToDo App Chevron down icon Chevron up icon
Chapter 5: Adding a REST API Chevron down icon Chevron up icon
Chapter 6: Deploying Genie Apps in Production Chevron down icon Chevron up icon
Chapter 7: Adding Authentication to Our App Chevron down icon Chevron up icon
Chapter 8: Developing Interactive Data Dashboards with Genie Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Full star icon 5
(1 Ratings)
5 star 100%
4 star 0%
3 star 0%
2 star 0%
1 star 0%
Emmett Jan 25, 2023
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Genie.jl is quickly becoming the industry standard in Julia. Not only is this framework useful and versatile, but it is incredibly easy to use! This book is one of the best, most organized, approaches to teaching web-development in Julia -- and there are not many tutorials online or otherwise that are going to give a better understand to this book.The book is co-written by one of the key creators of the Genie project, so in a lot of ways we almost get an " under-the-hood" understanding of the different topics. One thing I really enjoyed about the book is that it not only focuses on Julia Web-Development, but also data-bases, using Genie's Searchlight ORM, and all of the various different applications one night use the Genie framework for, such as interactive dashboards or simple APIs.All in all, Genie is a very powerful web-development Framework, and this book is a great way to learn how to use it! I would definitely recommend this book!
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

How do I buy and download an eBook? Chevron down icon Chevron up icon

Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.

If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.

Please Note: Packt eBooks are non-returnable and non-refundable.

Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:

  • You may make copies of your eBook for your own use onto any machine
  • You may not pass copies of the eBook on to anyone else
How can I make a purchase on your website? Chevron down icon Chevron up icon

If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:

  1. Register on our website using your email address and the password.
  2. Search for the title by name or ISBN using the search option.
  3. Select the title you want to purchase.
  4. Choose the format you wish to purchase the title in; if you order the Print Book, you get a free eBook copy of the same title. 
  5. Proceed with the checkout process (payment to be made using Credit Card, Debit Cart, or PayPal)
Where can I access support around an eBook? Chevron down icon Chevron up icon
  • If you experience a problem with using or installing Adobe Reader, the contact Adobe directly.
  • To view the errata for the book, see www.packtpub.com/support and view the pages for the title you have.
  • To view your account details or to download a new copy of the book go to www.packtpub.com/account
  • To contact us directly if a problem is not resolved, use www.packtpub.com/contact-us
What eBook formats do Packt support? Chevron down icon Chevron up icon

Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.

You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.

What are the benefits of eBooks? Chevron down icon Chevron up icon
  • You can get the information you need immediately
  • You can easily take them with you on a laptop
  • You can download them an unlimited number of times
  • You can print them out
  • They are copy-paste enabled
  • They are searchable
  • There is no password protection
  • They are lower price than print
  • They save resources and space
What is an eBook? Chevron down icon Chevron up icon

Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.

When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.

For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.