Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Tuesday, May 1, 2018

Using Microsoft SQL Server with Scala Slick

This blog post shows simple CRUD operations on Microsoft SQL Server using Scala Slick version 3.2.3. You might be thinking what’s really great about it? Duh! But until Scala Slick 3.2.x was released, using commercial databases was within the horizon of an additional closed source package know as Slick Extensions which supported Slick drivers for following databases
  1. Oracle
  2. IBM DB2
  3. Microsoft SQL Server


Library dependency used for Slick Extensions
libraryDependencies += "com.typesafe.slick" %% "slick-extensions" % "3.0.0"
But with the newer version of Slick, i.e 3.2.x these drivers are now available within the Slick core package as open source release which can also be seen from the change log as well.
If you find yourself struggling with a setup to make Microsoft SQL Server work with Scala Slick in your project, maybe because of the lack of resources available on the web, then read up further :)

TL;DR

SQL Server database configurations
sqlserver = {
 driver = "slick.jdbc.SQLServerProfile$"
 db {
 host = ${?SQLSERVER_HOST}
 port = ${?SQLSERVER_PORT}
 databaseName = ${?SQLSERVER_DB_NAME}

 url = "jdbc:sqlserver://"${sqlserver.db.host}":"${sqlserver.db.port}";databaseName="${sqlserver.db.databaseName}
 user = ${?SQLSERVER_USERNAME}
 password = ${?SQLSERVER_PASSWORD}
 }
}
Database instance
val dbConfig: DatabaseConfig[JdbcProfile] = DatabaseConfig.forConfig("sqlserver")
val db: JdbcProfile#Backend#Database = dbConfig.db

SBT project setup

For the example used in this blog post following dependencies and versions of respective artifacts are used
  1. Scala 2.11.11
  2. SBT 0.13.17
  3. Slick 3.2.3
  4. HikariCP 3.2.3
  5. Mssql JDBC 6.2.1.jre8
which inside our build.sbt file will look like the following set of instructions
name := "mssql-example"

version := "1.0"

scalaVersion := "2.11.11"

libraryDependencies ++= Seq(
 "com.typesafe.slick" %% "slick" % "3.2.3",
 "com.typesafe.slick" %% "slick-hikaricp" % "3.2.3",
 "com.microsoft.sqlserver" % "mssql-jdbc" % "6.2.1.jre8"
)
and the instructions of build.properties file will be
sbt.version = 0.13.17
The settings required to configure Microsoft SQL Server should go inside application.conffile, whose instructions would be to specify the details of our database

sqlserver = {
 driver = "slick.jdbc.SQLServerProfile$"
 db {
  host = ${?SQLSERVER_HOST}
  port = ${?SQLSERVER_PORT}
  databaseName = ${?SQLSERVER_DB_NAME}

  url = "jdbc:sqlserver://"${sqlserver.db.host}":"${sqlserver.db.port}";databaseName="${sqlserver.db.databaseName}
  user = ${?SQLSERVER_USERNAME}
  password = ${?SQLSERVER_PASSWORD}
 }
}
where it can be seen that SQLSERVER_HOST, SQLSERVER_PORT, SQLSERVER_DB_NAME, SQLSERVER_USERNAME and SQLSERVER_PASSWORD are to be provided as environment variables.
Now moving onto our FRM (Functional Relational Mapping) and repository setup, the following import will be used for MS SQL Server Slick driver’s API
import slick.jdbc.SQLServerProfile.api._
And thereafter the FRM will look same as the rest of the FRM’s delineated on the official Slick documentation. For the example on this blog let’s use the following table structure
CREATE TABLE user_profiles (
 id         INT IDENTITY (1, 1) PRIMARY KEY,
 first_name VARCHAR(100) NOT NULL,
 last_name  VARCHAR(100) NOT NULL
)
whose functional relational mapping will look like this:
class UserProfiles(tag: Tag) extends Table[UserProfile](tag, "user_profiles") {

 def id: Rep[Int] = column[Int]("id", O.PrimaryKey, O.AutoInc)

 def firstName: Rep[String] = column[String]("first_name")

 def lastName: Rep[String] = column[String]("last_name")

 def * : ProvenShape[UserProfile] = (id, firstName, lastName) <>(UserProfile.tupled, UserProfile.unapply) // scalastyle:ignore

}
Moving further up with the CRUD operations, they are fairly straightforward as per the integrated query model provided by Slick, which can be seen from the following UserProfileRepository class
class UserProfileRepository {

 val userProfileQuery: TableQuery[UserProfiles] = TableQuery[UserProfiles]

 def insert(user: UserProfile): Future[Int] =
  db.run(userProfileQuery += user)

 def get(id: Int): Future[Option[UserProfile]] =
  db.run(
   userProfileQuery
    .filter(_.id === id)
    .take(1)
    .result
    .headOption)

 def update(id: Int, firstName: String): Future[Int] =
  db.run(
   userProfileQuery
    .filter(_.id === id)
    .map(_.firstName)
    .update(firstName))

 def delete(id: Int): Future[Int] =
  db.run(userProfileQuery.filter(_.id === id).delete)
Lastly, in order to get the database instance using the configurations provided in application.conf file, the following code snippet can be used
val dbConfig: DatabaseConfig[JdbcProfile] = DatabaseConfig.forConfig("sqlserver")
val db: JdbcProfile#Backend#Database = dbConfig.db
Working codebase of this example is available at the following repository: scala-slick-mssql.
Also, if you’re interested in knowing how data can be directly streamed from PostgreSQL to a client using Akka Stream and Scala Slick then you might find the following article useful: Streaming data from PostgreSQL using Akka Streams and Slick in Play Framework
This blog post has been inspired by an endeavor to make Microsoft SQL Server work with Slick and an answer on StackOverFlow which is the reference of the configurations.
Hope this helps :)
This article was first published on the Knoldus blog.

Streaming data from PostgreSQL using Akka Streams and Slick in Play Framework

In this blog post I’ll try to explain the process wherein you can stream data directly from PostgreSQL database using Scala Slick (which is Scala’s database access/query library) and Akka Streams (which is an implementation of Reactive Streams specification on top of Akka toolkit) in Play Framework. The process is going to be pretty straightforward in terms of implementation where data is read from one of the tables in your SQL database as stream and then it is sent/streamed to one of the REST end point configured to download this data.



For better understanding let’s take an example of an application or service which is used for administering a huge customer base of an organisation/company. The person involved in administering the customer base wants to get the entire data-set of customers for let’s say auditing purpose. Based on requirements it would sometimes make sense to stream this data directly into a downloadable file which is what we are going to do in this blog post.
(For this blog post you should have a basic knowledge of using Play Framework and Slick library)

The example uses following dependencies
  1. Play Framework 2.6.10 (“com.typesafe.play” % “sbt-plugin” % “2.6.10”)
  2. Play-Slick 3.0.1 (“com.typesafe.play” %% “play-slick” % “3.0.1”)
  3. Akka Streams 2.5.8 (“com.typesafe.akka” %% “akka-stream” % “2.5.8”)
  4. PostgreSQL 42.1.4 (“org.postgresql” % “postgresql” % “42.1.4”)
Let’s start by assuming we have a customer table in our PostgreSQL database which has the following structure

CREATE TABLE customers (
  id        BIGSERIAL PRIMARY KEY,
  firstname VARCHAR(255) NOT NULL,
  lastname  VARCHAR(255),
  email     VARCHAR(255)
);
Slick’s functional relational mapping corresponding to this table structure should look like this
case class Customer(id: Long,
                    firstName: String,
                    lastName: String,
                    email: String)

trait CustomerTable extends HasDatabaseConfigProvider[slick.jdbc.JdbcProfile] {
  
  import profile.api._

  val customerQuery: TableQuery[CustomerMapping] = TableQuery[CustomerMapping]

  private[models] class CustomerMapping(tag: Tag) extends Table[Customer](tag, "customers") {

    def id: Rep[Long] = column[Long]("id", O.PrimaryKey, O.AutoInc)

    def firstName: Rep[String] = column[String]("firstname")

    def lastName: Rep[String] = column[String]("lastname")

    def email: Rep[String] = column[String]("email")

    def * : ProvenShape[Customer] = (id, firstName, lastName, email) <>(Customer.tupled, Customer.unapply)

  }

}
Now let’s use the customerQuery to get data from the customers table in the form of DatabasePublisher of type Customer, i.e DatabasePublisher[Customer], which is Slick’s implementation of reactive stream’s Publisher where Publisher is the (potential) unbounded sequence of elements that publishes the elements according to the demand from the Subscriber. We will define this inside CustomerRepository.

def customers: DatabasePublisher[Customer] =
  db.stream(
    customerQuery
      .result
      .withStatementParameters(
         rsType = ResultSetType.ForwardOnly,
         rsConcurrency = ResultSetConcurrency.ReadOnly,
         fetchSize = 10000)
      .transactionally)
Certain things to be noted when using PostgreSQL for streaming data/records, which is also noted in Slick’s Official documentation:
  1. The use of transactionally which enforces the code to run on a single Connection with auto commit set as false [setAutoCommit(false)], by default slick is set to run in auto commit mode.
  2. The use of fetchSize so that the JDBC driver does not fetch all rows to the memory (i.e on client side) at once but instead fetch the specified number of rows at a time.
  3. ResultSetType.ForwardOnly sets the type to allow results to be read sequentially so that the cursor will only move forward.
  4. ResultSetConcurrency.ReadOnly makes sure that the ResultSet may not be updated.
Only if all of the above is done will the streaming work properly for PostgreSQL else it won’t and the actions inside the stream behavior will fetch the entire dataset.
So, the database repository code base is now sorted out. Let’s focus on the controller and how it’ll stream this data to a downloadable file.
We can create a new Play controller for the purpose of managing all APIs related to the customers and this controller has access to the CustomerRepository we created earlier in which the customers method is defined and implemented.
We’ll use Play’s simple Result to stream the data to our client, i.e to the person administering the customers on /customers API (added to Play routes) by providing the customer stream to HttpEntity.Streamed case class like this
Result(
      header = ResponseHeader(OK, Map(CONTENT_DISPOSITION → s"attachment; filename=customers.csv")),
      body = HttpEntity.Streamed(csvSource, None, None))
The entire controller method would look something like this
def customers: Action[AnyContent] = Action { implicit request =>
  val customerDatabasePublisher = customerRepository.customers
  val customerSource = Source.fromPublisher(customerDatabasePublisher)

  val headerCSVSource = Source.single(ByteString(""""First Name","Last Name","Email"""" + "\n"))
  val customerCSVSource =
    customerSource.map(data => ByteString(s""""${data.firstName}","${data.lastName}","${data.email}"""" + "\n"))
  
  val csvSource = Source.combine(headerCSVSource, customerCSVSource)(Concat[ByteString])

  Result(
        header = ResponseHeader(OK, Map(CONTENT_DISPOSITION → s"attachment; filename=customers.csv")),
        body = HttpEntity.Streamed(csvSource, None, None))
}
Note that the DatabasePublisher[Customer] is converted to Source of Customer using the Source.fromPublisher helper method which is used to create a Source from Publisher.
Rest of the manipulations are done on the Source to convert the data into readable CSV file format.
Also, note the use of Source.combine method which is used to combine sources with fan-in strategy which in our case is Concat.
Hope this helps :)
The entire code base is available in the following repository playakkastreams.
This article was first published on the Knoldus blog.

Parallelism in Clojure

An axiom of microprocessor development stating that the number of transistors on integrated circuits doubles approximately every two years is analogous to the fact the processing power doubles during the same period, relative to the cost or size. This has lead to the need of parallelism in programming languages and Clojure is one such language which provides a variety of functions for your multi-threaded code. In this article we’ll discuss about futures, atoms and refs which are all a consequential part of parallel programming.


Futures
Futures are supported out-of-box in clojure. They can be used to simply start a new memory intensive operation in a new thread which typically runs in a thread pool. Dereferencing a future may yield a result immediately or it will block until the future is done.
Let’s start with an example of a memory intensive operation. Here, we will try to write a range of numerical values in separate files, with each write operation for a file done with a separate future.
1
2
3
4
5
6
7
user=> (def a
 #_=>      (doall
 #_=>         (map
 #_=>            (fn [n] (future (spit (str (gensym "test") ".txt")
 #_=>                                        (apply str (doall (map inc (range n)))))))
 #_=>            [10000000 1000000 10000000])))
 #'user/a

In the above code doall causes the entire lazyseq to reside in memory at one time. As “map” maps through the vector of length 3, so 3 futures are started where each future starts a new spit operation on test[random number].txt files to write the range of numbers defined by the vector “[10000000 1000000 10000000]”. The above code will return a lazyseq of futures which will be stored in “a”.
Now let’s check when the future gets completed by using the following code:


1
2
3
4
user=> (map future-done? a)
 (false true false)
 user=> (map future-done? a)
 (true true false)

future-done? returns true if the following future is done. On my system the future operation with range of “10000000” takes more time as compared to the range of “1000000”.
So, “(map future-done? a)” for the first time returns (false true false), meaning that the second future is done but the first and third futures are still processing.
After awhile, “(map future-done? a)” returns (true true false), meaning that first and second futures are done.
The order of completion of futures may vary on your system, but eventually all will be done after awhile. This means that you can offload heavy operations in different threads and continue with other tasks.


Atoms
In the most simple terms atoms are uncoordinated and synchronous. We use atoms only when one identity needs to be updated synchronously. Synchronous access means that all values are updated before continuing further with the next update. Atoms simply ensures that in a multi-threaded environment the values of atom are either updated entirely or not at all.
We’ll start with the most basic example:
1
2
3
4
user=> (def a (atom {:firstname "" :lastname ""}))
 #'user/a
 user=> @a
 {:firstname "", :lastname ""}

Here we’ve defined a map as an atom. In order to find the value stored in an atom we use deref or a short form of deref “@”. Dereferencing returns the value stored in “a”, in this case we get the map defined during initialization.
To change the value of an atom we can either use swap! or reset!


1
2
user=> (swap! a #(assoc % :firstname %2 :lastname %3) "Sidharth" "Khattri")
 {:firstname "Sidharth", :lastname "Khattri"}

swap! takes atom as the first argument and the function to apply on the value stored in the atom as the second argument. In the above case we’ve defined an anonymous function that associates a new value to the previously defined map and returns that new value. Internally swap! applies compare-and-set! on the new values to cross check for any race conditions. If their exist a race condition i.e if two threads are trying to apply same function on the atom simultaneously and if the value of the atom has changed since they first began swapping, the loser thread will try to swap again until the present value is same as the last commit.

1
2
user=> (reset! a 1)
 1

reset! sets the value of atom to a new value without regard for the previously stored value in the atom.
Refs
Unlike atoms, refs are coordinated and are used for synchronous access. They are used when multiple identities have to be changed synchronously and they use Software Transactional Memory System (STM) for memory transactions. Any changes to the values of refs have to be done in transactional blocks, i.e sync or dosync.
Refs are defined in the same way atoms are defined:
1
2
3
4
user=> (def task-to-be-done (ref #{1,2,3,4,5}))
 #'user/task-to-be-done
 user=> (def task-done (ref #{}))
 #'user/task-done

Here, we have defined two tasks that have to be updated simultaneously, i.e task-to-be-done and task-done, which are defined as refs containing hashsets.


1
2
3
4
5
user=> (defn update-values [value]
 #_=>      (dosync
 #_=>        (alter task-to-be-done disj value)
 #_=>          (alter task-done conj value)))
 #'user/check

Then we define a function – update-values, to alter the values of both the refs simultaneously in the dosync transactional block. “alter” is used to change the in-transactional-value of the refs. “disj” returns a new set that does not contain the key(s) passed as the argument. Similarly, “conj” returns a new set that contains the key(s) passed as the argument.

1
2
3
4
5
6
user=> (update-values 1)
 #{1}
 user=> @task-to-be-done
 #{2 3 4 5}
 user=> @task-done
 #{1}

On passing some value to “update-values” function, the values of both refs are updated simultaneously. In order to view the values stored in refs we use the same deref or “@” as used in atoms. Dereferencing task-to-be-done and @task-done returns the values stored in the refs.
Thus refs are used for managing multiple data structures in transactional blocks, atomically.
This article was first published on the Knoldus blog.

How to setup and use Zookeeper in Scala using Apache Curator

In order to use Zookeeper to manage your project’s configurations across the cluster, first we will setup the zookeeper ensemble on our local machine (setup is for testing on a single machine) by following these steps:


1) Download a stable zookeeper release
2) Unpack it at three places and rename it to:
1
2
3
/home/user/Desktop/zookeeper1,
/home/user/Desktop/zookeeper2, and
/home/user/Desktop/zookeeper3

3) In order to use zookeeper we will need to setup configuration files for all servers.
Make a new file zoo.cfg,
/home/user/Desktop/zookeeper1/conf/zoo.cfg
and add following details:
1
2
3
4
5
6
7
8
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/user/Desktop/zookeeperData1
clientPort=2181
server.1= localhost:2888:3888
server.2= localhost:2889:3889
server.3= localhost:2890:3890

Similarly,
/home/user/Desktop/zookeeper2/conf/zoo.cfg, as:

1
2
3
4
5
6
7
8
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/user/Desktop/zookeeperData2
clientPort=2182
server.1= localhost:2888:3888
server.2= localhost:2889:3889
server.3= localhost:2890:3890

And,
/home/user/Desktop/zookeeper3/conf/zoo.cfg, as:

1
2
3
4
5
6
7
8
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/home/user/Desktop/zookeeperData3
clientPort=2183
server.1= localhost:2888:3888
server.2= localhost:2889:3889
server.3= localhost:2890:3890

4) Now we will have to define each server’s id by making a new file in:
/home/user/Desktop/zookeeperData1/myid
which should have: 1
/home/user/Desktop/zookeeperData2/myid
which should have: 2
/home/user/Desktop/zookeeperData3/myid
which should have: 3
5) Next, we will start zookeeper ensemble for each server in 3 different terminals:
cd /home/user/Desktop/zookeeper1
bin/zkServer.sh start
cd /home/user/Desktop/zookeeper2
bin/zkServer.sh start
cd /home/user/Desktop/zookeeper3
bin/zkServer.sh start
6) Now we will add some data in one of the ZNode of the zookeeper ensemble by following steps:
a) bin/zkCli.sh
b) create /test_node “Some data”
7) Then we will write the following code in order to setup a watcher for zookeeper node so as to get stored data from zookeeper server using apache curator as a library to interact with our zookeeper server.
Add the following dependency in your build.sbt file:
1
2
3
4
libraryDependencies ++= Seq(
"org.apache.curator" % "curator-framework" % "2.6.0",
"org.apache.curator" % "curator-recipes" % "2.6.0"
)

and use this to interact with the zookeeper server:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class ZookeeperClient {
 
 private val logger = LoggerFactory.getLogger(this.getClass.getName)
 
 def main(args: Array[String]) = {
  val retryPolicy = new ExponentialBackoffRetry(1000, 3)
  val curatorZookeeperClient = CuratorFrameworkFactory.newClient("localhost:2181,localhost:2182,localhost:2183", retryPolicy)
  curatorZookeeperClient.start
  curatorZookeeperClient.getZookeeperClient.blockUntilConnectedOrTimedOut
  val znodePath = "/test_node"
  val originalData = new String(curatorZookeeperClient.getData.forPath(znodePath)) // This should be "Some data"
 
  /* Zookeeper NodeCache service to get properties from ZNode */
  val nodeCache = new NodeCache(curatorZookeeperClient, znodePath)
  nodeCache.getListenable.addListener(new NodeCacheListener {
 
  @Override
  def nodeChanged = {
   try {
    val dataFromZNode = nodeCache.getCurrentData
    val newData = new String(currentData.getData) // This should be some new data after it is changed in the Zookeeper ensemble
   } catch {
    case ex: Exception => logger.error("Exception while fetching properties from zookeeper ZNode, reason " + ex.getCause)
   }
  }

  nodeCache.start
  })
 }
}


This article was first published on the Knoldus blog.

Monday, April 30, 2018

Google Sign-In using Clojure

Last time I wrote an article for providing Facebook Sign-In using Clojure. This article will guide you to add Google Sign-In functionality in your web application using clojure. We’ll use compojure.core for routing, clj-http.client for http requests, cheshire.core for parsing json and noir.response for redirections.


First, make a new google project to get your project’s Client ID and Client Secret Key from this URL: https://console.developers.google.com/project.

Now define a new namespace as:
1
2
3
4
5
(ns exampleapp.routes.google
 (:use compojure.core)
 (:require [clj-http.client :as client]
           [cheshire.core :as parse]
           [noir.response :as resp]))

In “google” namespace, define following variables:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
(def CLIENT_ID "your project's client id")
(def REDIRECT_URI "http://localhost:3000/auth_google")
(def login-uri "https://accounts.google.com")
(def CLIENT_SECRET "your project's client secret key")
(def google-user (atom {:google-id "" :google-name "" :google-email ""}))
 
(def red (str "https://accounts.google.com/o/oauth2/auth?"
              "scope=email%20profile&"
              "redirect_uri=" (ring.util.codec/url-encode REDIRECT_URI) "&"
              "response_type=code&"
              "client_id=" (ring.util.codec/url-encode CLIENT_ID) "&"
              "approval_prompt=force"))

“red” defines the request url on which the user is redirected to ask for user permission for user details. We use ring.util.codec/url-encode to encode the url details. ring.util.codec/url-encode uses UTF-8 encoding by default.
Define routes in “google” namespace in order to redirect a user to the url defined by “red” as follows:

1
2
(defroutes google-routes
 (GET "/google" [] (resp/redirect red)))

After user provides permission to your google project, you will get an authorization code on the the redirect uri that you mentioned in your google project, the same that you defined in your namespace, i.e http://localhost:3000/auth_google.
Now define a new route in google-routes as:

1
2
(GET "/auth_google" {params :query-params}
 (google params))

and a new function in order to get the access code and user details as:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
(defn google [params]
 (let [access-token-response (client/post "https://accounts.google.com/o/oauth2/token"
                                          {:form-params {:code (get params "code")
                                                         :client_id CLIENT_ID
                                                         :client_secret CLIENT_SECRET
                                                         :redirect_uri REDIRECT_URI
                                                         :grant_type "authorization_code"}})
       user-details (parse/parse-string (:body (client/get (str "https://www.googleapis.com/oauth2/v1/userinfo?access_token="
 (get (parse/parse-string (:body access-token-response)) "access_token")))))]
 (swap! google-user #(assoc % :google-id %2 :google-name %3 :google-email %4) (get user-details "id") (get user-details "name") (get user-details "email"))))

In the above function we use clj-http’s “post” to make a post request to get access token followed by “get” to get user information. Then we use cheshire.core’s “parse-string” to parse json response and convert it into clojure object and save the information in the atom defined as “google-user”.
Entire “google” namespace is as follows:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
(ns exampleapp.routes.google
 (:use compojure.core)
 (:require [clj-http.client :as client]
           [cheshire.core :as parse]
           [noir.response :as resp]))
 
(def CLIENT_ID "your project's client id")
(def REDIRECT_URI "http://localhost:3000/auth_google")
(def login-uri "https://accounts.google.com")
(def CLIENT_SECRET "your project's client secret key")
(def google-user (atom {:google-id "" :google-name "" :google-email ""}))
 
(def red (str "https://accounts.google.com/o/oauth2/auth?"
              "scope=email%20profile&"
              "redirect_uri=" (ring.util.codec/url-encode REDIRECT_URI) "&"
              "response_type=code&"
              "client_id=" (ring.util.codec/url-encode CLIENT_ID) "&"
              "approval_prompt=force"))
 
(defn google [params]
 (let [access-token-response (client/post "https://accounts.google.com/o/oauth2/token"
                                          {:form-params {:code (get params "code")
                                           :client_id CLIENT_ID
                                           :client_secret CLIENT_SECRET
                                           :redirect_uri REDIRECT_URI
                                           :grant_type "authorization_code"}})
       user-details (parse/parse-string (:body (client/get (str "https://www.googleapis.com/oauth2/v1/userinfo?access_token="
 (get (parse/parse-string (:body access-token-response)) "access_token")))))]
 (swap! google-user #(assoc % :google-id %2 :google-name %3 :google-email %4) (get user-details "id") (get user-details "name") (get user-details "email"))))
 
(defroutes google-routes
 (GET "/auth_google" {params :query-params}
 (google params))
 
(GET "/google" [] (resp/redirect red)))

This article was first published on the Knoldus blog. 

Facebook Sign-in using Clojure

In order to provide Facebook sign-in functionality you need to create a new Facebook App from this url: https://developers.facebook.com/docs/facebook-login. Provide the redirection URI that you’ll use for the App. After setting up the app you’ll get an App ID and App Secret key.



We’ll use “clj-oauth2.client” to redirect a user to the authentication page, “clj-http.client” for HTTP requests, “cheshire.core” to parse Json string in order to get keywords, “noir.respose” to provide re-directions and “compojure.core” for routing.
We’ll begin with defining a new namespace:
1
2
3
4
5
6
(ns exampleapp.routes.facebook
 (:use compojure.core)
 (:require [clj-oauth2.client :as oauth2]
           [noir.response :as resp]
           [clj-http.client :as client]
           [cheshire.core :as parse]))

In facebook namespace define an atom, facebook-user, to store Facebook user details:
1
2
(def facebook-user
  (atom {:facebook-id "" :facebook-name "" :facebook-email ""}))

Now include the App ID and App Secret key you just got after creating a new Facebook app along with the redirection URI, in the code below:
1
2
3
(def APP_ID "your app id")
(def APP_SECRET "your app secret key")
(def REDIRECT_URI "http://localhost:3000/auth_facebook")

and define an oauth2 map containing all the details required for Facebook log in:
1
2
3
4
5
6
7
8
9
(def facebook-oauth2
 {:authorization-uri "https://graph.facebook.com/oauth/authorize"
  :access-token-uri "https://graph.facebook.com/oauth/access_token"
  :redirect-uri REDIRECT_URI
  :client-id APP_ID
  :client-secret APP_SECRET
  :access-query-param :access_token
  :scope ["email"]
  :grant-type "authorization_code"})

We can use “make-auth-request” function defined in “clj-oauth2.client” library to get the redirect URI on which the user should be redirected. The user can now give access to the app we created in first step.

1
2
(resp/redirect
  (:uri (oauth2/make-auth-request facebook-oauth2)))

Note that we used noir.response/redirect function to provide the redirection.
After a Facebook user grant access to the app, we’ll get a response containing access token on the redirection URI we provided while setting up our Facebook app. We’ll use “compojure.core’s” GET to get the response:

1
2
(defroutes facebook-routes
 (GET "/auth_facebook" {params :query-params} (facebook params)))

and pass it to a function in order to get the access token and user details.
We’ll use the code below for getting access token and user details:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
(defn facebook [params]
 (let [access-token-response (:body (client/get (str "https://graph.facebook.com/oauth/access_token?"
                                                     "client_id=" APP_ID
                                                     "&redirect_uri=" REDIRECT_URI
                                                     "&client_secret=" APP_SECRET
                                                     "&code=" (get params "code"))))
       access-token (get (re-find #"access_token=(.*?)&expires=" access-token-response) 1)
       user-details (-> (client/get (str "https://graph.facebook.com/me?access_token=" access-token))
                        :body
                        (parse/parse-string))]
  (swap! facebook-user
   #(assoc % :facebook-id %2 :facebook-name %3 :facebook-email %4)
     (get user-details "id")
     (get user-details "first_name")
     (get user-details "email"))))

This article was first published on the Knoldus blog.