Giter Club home page Giter Club logo

arrowinpractice's Introduction

Build Status

Arrow in practice

Lambda.World Cádiz 2018 workshop hosted by @JorgeCastilloPR and @raulraja from @47Degrees.

This workshop starts with a basic RESTful API coded using ktor (@JetBrains). Our intention is to iterate over it converting it to a more functional style by putting Arrow into practice.

Some key points you'll learn:

  • How to handle absent values incoming from an HttpRequest with the Arrow data types.
  • How lift values and raise errors inside the context of IO
  • How to defer side effecting and exception throwing computations with IO
  • How to recover from failed computations in the context of IO
  • How to reduce a set of potential values into a single one with fold
  • How to encode sequential operations with Monad Comprehensions.
  • How to encode non-dependent operations using the Applicative Builder.

Exercises

1a. Handling nullability

When starting a project with Arrow first go to arrow-kt.io to include the necessary dependencies. The dependencies used in this work shop are included below for convenience

compile "io.arrow-kt:arrow-effects-instances:$arrow_version"
compile "io.arrow-kt:arrow-instances-data:$arrow_version"

To enable Arrow in your project include these dependencies in the dependencies section in build.gradle file: the run:

./gradlew clean build

All details endpoint implementations are non optional typed values now coming from the Database. These values may be absent when using an Id to look them up. You must translate that concern to a FP related data type such as arrow.core.Option. Make the function com.fortysevendeg.arrowinpractice.workshop.ex1.paramOf located at com/fortysevendeg/arrowinpractice/endpoints/CharacterDetails.kt return an Option<String> instead of a String?.

To double check your changes, run com.fortysevendeg.arrowinpractice.workshop.ex1.WorkshopTests suite.

You may run this test in IntelliJ IDEA (right click and Run in the test file) or via the command line with:

./gradlew test --tests "com.fortysevendeg.arrowinpractice.workshop.ex1.WorkshopTests"

Once this exercise is completed the following test should pass:

  • 1a should extract params from request

If you want to keep test running while making changes you may prepend the -t modifier to the after --tests in the command above.

Reference Links:

1b. Folding over optional values

Once we receive the endpoint parameters as Option<String> we need to contemplate the Some and None cases. You may use here when or fold in order to contemplate both Some and None cases.

Modify com.fortysevendeg.arrowinpractice.workshop.ex1.idOrNotFound such as that if a value is found it's returned in IO and if the value is missing we raise a NotFoundException error in IO.

Once this exercise is completed the following test should pass:

  • 1b should return a character Id or a raised NotFound exception in the context of IO
  • 1b should return a NotFound exception in the context of IO when an id is not found

Reference Links:

1c. Handling and recovering from errors

Converting string to long values may fail with an exception since it relies in a third party api String.toLong. Modify com.fortysevendeg.arrowinpractice.workshop.ex1.stringIdToLong so it captures this effect in IO and translates any thrown exceptions to a InvalidIdException. This may be implemented in a few different ways depending on whether you use handleErrorWith, attempt + fold + just/raiseError, etc.

Once this exercise is completed the following test should pass:

  • 1c should properly handle String#toLong with valid Long values
  • 1c should properly handle String#toLong raising errors as InvalidIdException

Reference Links:

1d. Returning db results and raising errors for missing db objects

When querying the database with a set of Long values the returned objects may not be found if the ids are not recognized in the db. Return the db object in the context of IO or raise a NotFoundException when the db returns an absent value.

Once this exercise is completed the following test should pass:

  • 1d fetch a character by id from the database for a given valid character id
  • 1d fetch a character by id from the database results in a NotFound raised error for invalid ids

Reference Links:

1e. Translating raised errors in the context of IO

Handle all database errors in com.fortysevendeg.arrowinpractice.workshop.ex1.handleDBExceptions so that NotFoundException is preserved but all other exceptions are translated into InvalidIdException. You may use handleErrorWith to recover from existing errors.

Once this exercise is completed the following test should pass:

  • 1e handle DB exceptions preserving NotFoundExceptions
  • 1e handle DB exceptions preserving NotFoundExceptions but translating all others to InvalidIdException

2a. Translating raised errors in the context of IO

When handling multiple ids for unrelated database objects we may independently fetch the objects Applicative vs explicitly fetching them one after another Monad.

Once this exercise is completed the following test should pass:

  • 1e handle DB exceptions preserving NotFoundExceptions
  • 1e handle DB exceptions preserving NotFoundExceptions but translating all others to InvalidIdException

Reference Links:

Solutions

You can get a working workspace where all test pass with solutions in the solutions git tag.

git fetch --all --tags --prune
git checkout solutions

Or revert back to the original workshop state with

git fetch --all --tags --prune
git checkout workshop

License

Copyright (C) 2018 47 Degrees

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.