85
www.erlang-solutions.com SWIFTBA MEETUP JUNE 8th, 2016 @ Inaka's Offices

Writing a REST Interconnection Library in Swift

Embed Size (px)

Citation preview

Page 1: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

SWIFTBA MEETUP

JUNE 8th, 2016@ Inaka's Offices

Page 2: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

HELLO!

Pablo Luciano [email protected]

@pablolvillar

www.erlang-solutions.com www.inaka.net

_iOS dev since 2011

_swifter since 2015

Page 3: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

#warilis

Page 4: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

writingarestinterconnectionlibraryinswift_

Page 5: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

ROADMAP

1. Motivation

2. Architectural concept

3. Implementation

Page 6: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

1.MOTIVATION

Page 7: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Why would we need a REST interconnection library?

Our App

ServerBackend

Give me a list with all the users

200: Success, returns

JSON array with users

Page 8: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Why would we need a REST interconnection library?

Create a user with this info: [...]

200: Success,

user created

Our App

ServerBackend

Page 9: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Why would we need a REST interconnection library?

Update some info for this user:

[...]

200: Success, returns

user updated

Our App

ServerBackend

Page 10: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Delete this user: [...]

200: Success,

user deleted

Why would we need a REST interconnection library?

Our App

ServerBackend

Page 11: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Why would we need a REST interconnection library?

C/R/U/D

Response

Our App

ServerBackend

Page 12: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

● NSURLSession

● Alamofire / AFNetworking

● Other libraries

How we usually write networking code:

Page 13: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

NSURLSession example: "Give me a list with all the users"

GET /users

How we usually write networking code:

Page 14: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Now, where should that networking code go…?

Page 15: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Premises:

● Find a good place to put our networking code.

● Define a proper way to architecture our REST layer.

● Avoid duplicated code from common CRUD operations.

● Come up with a concise API that we can use across all of our projects.

Page 16: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

2.ARCHITECTURALCONCEPT

Page 17: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

GOAL: Provide a neat API

that our ViewControllers can interact withwithout having to worry about networking implementation details.

Page 18: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's find out common paths...

"Give me a list with all the users" GET /users

"Give me the details for this user" GET /users/:id

"Create a user with this data" POST /users

"Update this user with this data" PUT /users/:id

"Delete this user" DELETE /users/:id

Page 19: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's find out common paths...

"Give me a list with all the users" GET /users

"Give me the details for this user" GET /users/:id

"Create a user with this data" POST /users

"Update this user with this data" PUT /users/:id

"Delete this user" DELETE /users/:id

Page 20: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's find out common paths...

"Give me a list with all the posts" GET /posts

"Give me the details for this post" GET /posts/:id

"Create a post with this data" POST /posts

"Update this post with this data" PUT /posts/:id

"Delete this post" DELETE /posts/:id

Page 21: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Page 22: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

"Give me a list with all the entities" GET /:name

"Give me the details for this entity" GET /:name/:id

"Create an entity with this data" POST /:name

"Update this entity with this data" PUT /:name/:id

"Delete this entity" DELETE /:name/:id

Let's introduce the entity concept...

Page 23: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

"Give me a list with all the entities" GET /:name

"Give me the details for this entity" GET /:name/:id

"Create an entity with this data" POST /:name

"Update this entity with this data" PUT /:name/:id

"Delete this entity" DELETE /:name/:id

Notice that any entity needs an id to work

Page 24: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

User Post Comment

id Create?

Read?

Update?

Delete?

Entity

Page 25: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

REPOSITORY!

Actually, we need a different place from which we can perform CRUD operations to our entity…

Entity

CreateReadUpdateDelete

And that place is called…

Page 26: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

UserRepository

User

findAll() → [User]

findByID(id) → User

create(User)

update(User)

delete(User)

Page 27: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Elemental CRUD operations*

Repository

Entity

findAll() → [Entity]

findByID(id) → Entity

create(Entity)

update(Entity)

delete(Entity)

Page 28: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

PostRepository

Post

findAll() → [Post]

findByID(id) → Post

create(Post)

update(Post)

delete(Post)

Customization

findPostsFromUser(User) → [Post]

Page 29: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

*

Page 30: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

This one has the issue that every repository you create will come with all these basic CRUD methods by default, even if any particular repository doesn't need all of them.

That breaks the YAGNI principle.

But still, it's a very convenient approach for us.

* There are many ways to approach the Repository pattern.

Page 31: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

name

Our Repository needs a name to work

Repository

Entity findAll() → [Entity]

findByID(id) → Entity

create(Entity)

update(Entity)

delete(Entity)

GET /:name/

GET /:name/:id

POST /:name

PUT /:name/:id

DELETE /:name/:id

Page 32: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

UserRepository

findAll() → [User]

findByID(id) → User

create(User)

update(User)

delete(Entity)

GET /users/

GET /users/:id

POST /users

PUT /users/:id

DELETE /users/:id

This name represents the group of entities that the repository works with

"users"

User

Page 33: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Last, but not least…

We still need to define a place where our networking code will fall into.

Let's introduce the concept of…

BACKEND

Page 34: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Repository Backend

GET/users Networking

code

Page 35: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Repository NSURLSessionBackend

GET/users NSURLSession

code

Page 36: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Repository AlamofireBackend

GET/users Alamofire

code

Page 37: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Repository TestingBackend

GET/users Sample code

(mocks)

Page 38: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Repository Backend

GET/users Networking

code

Raw Data

Parsing??

Page 39: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Raw Data

Parsing

UserRepository

NSURLSessionBackend

GET/users

UsersListViewController .findAll()

Users

Page 40: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

3.IMPLEMENTATION

Page 41: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's translate all these diagrams into code.

Not just any code, but…

Swift code!

Page 42: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Where to start…?

OK, let's do Repository

Page 43: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

✔ Protocol composition

✔ Generics

- Prefer composition over inheritance whenever possible.

- This way, you end up having a more flexible and extendable architecture.

- By using generics, you lead your models to become more adaptive and customizable.

- The final user is going to be happier.

Page 44: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Before proceeding, let's introduce two new friends you should become familiar with...

● Result

● Future

Page 45: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

● Result- It's an enum that we're going to use to represent

a result.

- It can be either:

- Success (and hold a relevant result value)

- Failure (and hold a relevant error)

Page 46: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

● Result

e. g. [User]

e. g. NSError

Page 47: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

● Future- You should definitely check out this talk:

- https://realm.io/news/swift-summit-javier-soto-futures/

- Anyway, roughly speaking, a Future is a struct

that we're going to use to represent the

computation of an asynchronous task.

Page 48: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

- Here you can see why it's convenient to use Futures:

Page 49: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Page 50: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

.map and .andThen are 2 special functions in Futures that allow us to chain asynchronous operations very nicely.

Page 51: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

● Future- Let's create a function that returns a Future:

This Future is going to work with a Result<[User], NSError>

Page 52: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

- Let's use that Future:

let result:(Result<[User], NSError>)

Type inference

let users: [User]

let error: NSError

Page 53: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

✔ Static typing / Type inference

✔ Enums with associated values

- Compiler enforces you to use the types you're expected to use.

- Write less, know more.

- We're getting all the juice from Swift enums by using them with associated values.

- This allows us to define powerful structures to represent discrete values containing relevant information in a proper way.

Page 54: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Now, let's add elemental CRUD functionality to our Repository...

Page 55: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

We can add default implementations for those in a protocol extension:

Page 56: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's analyze how we would implement one of those…

Page 57: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's add a Backend at the Repository level...

Page 58: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's define a Backend:Associated type: String

Means that any case will

have a .rawValue of type

String.

"GET" "POST" "PUT" "DELETE"

come by default

Page 59: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's (finally) add a Backend at the Repository level...

Page 60: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

let future:Future<NSData?, NSError>

Type inference ≠Parsing

Page 61: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

=

Page 62: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Page 63: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Now, let's define a concrete Backend that we can actually use...

Page 64: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Now, let's define a concrete Backend that we can actually use...

Page 65: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

URL checking We're going to improve this.

Later. Promise.

Serverlinking

Dependency

Page 66: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

We need variables to hold these. Also, it would be cool to be able to inject them.

Page 67: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's go back a bit to our NSURLSessionBackend definition...

We need to hold state, so we need a class.

Page 68: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's define our configuration object

Page 69: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

We can use constructor injection in our NSURLSessionBackend...

With default values

Remember: Using dependency injection helps unit-testing.

Page 70: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

✔ Dependency Injection

✔ Enums with raw values

- Initializers with default values in their parameters encourage constructor injection.

- Once again, Swift eases unit-testing.

- Enums can be associated to a type so that their cases hold a .rawValue of that type.

- You can define their raw values by your own, or let the compiler do its magic and use the defaults.

Page 71: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Now the question is, why the hell are we still using NSError??

Page 72: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Alright, let's customize!

Page 73: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Let's enhance our error handling...

All of these do not appear as errors in the networking process...We usually get a success response with a status code that WE should interpret as an error, depending on the code (e.g. a 500).

Page 74: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Now, let's talk about parsing...

Do I have time to talk about this?

YES / NO

Page 75: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

OK, let's talk about parsing...

User[String: AnyObject]

a.k.a. "Dictionary"

conversion

Page 76: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

To the server

OK, let's talk about parsing...

User[String: AnyObject]

create()update()

DictionaryRepresentable

Page 77: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

OK, let's talk about parsing...

User[String: AnyObject]

read()

From the server

DictionaryInitializable

Page 78: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

From dictionary / To dictionary

In case there's a parsing error (e.g. a missing field).

Remember: You should NEVER initialize an invalid object.

Page 79: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

From dictionary, example:

Page 80: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

To dictionary, example:

Page 81: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

✔ ErrorType

✔ Throws

- Error handling has been enhanced in Swift.

- Now you can define your own errors, which combined with the power of enums and pattern matching allow you to work in a cleaner way.

- Throwable initializers encourage better exceptions handling mechanisms, such as try/catch.

- As we saw, you can make your initializers throw any discrete ErrorType that you define.

Page 82: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

https://github.com/inaka/JaymeMeet Jayme

✓ Open Source

✓ Issues are welcome

✓ So are Pull Requests

Jayme is basically what we just built, with some other enhancements that I haven't talked about because of time, for example:

● Pagination support (PagedRepository)● More generalization (Backend is more abstract)

Page 83: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Meet Jayme https://github.com/inaka/Jayme

Page 84: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

Meet Jayme https://github.com/inaka/Jayme

Page 85: Writing a REST Interconnection Library in Swift

www.erlang-solutions.com

THANK YOU!

Any [email protected]

@pablolvillar