/monzo-vapor

Server-side Swift package for Monzo APIs

Primary LanguageSwiftMIT LicenseMIT

Monzo Client for Vapor

Swift

A Monzo client that provides an interface to the public Monzo API. It's built around Vapor, and designed for usage in server-side Swift environments.

Inspiration was taken from monzo-swift, and for a UIKit solution take a look at MondoKit.

Whilst I've made as much effort to make errors as informative as possible, I recommend checking out the Monzo Docs

Also I highly recommend joining the Monzo Developers Slack group. I couldn't have done this project without the great community on there!

Requirements

This framework is designed to work against Swift 3.1, and Vapor 2.0

Installation

Installation is done using Swift Package Manager, open your Package.swift file and add a new dependency!

import PackageDescription

let package = Package(
    dependencies: [
        .Package(url: "https://github.com/Sherlouk/monzo-vapor.git", majorVersion: 1),
    ]
)

Getting Started

Initialise a client

A MonzoClient acts as a way to bind all users, authorisation and API requests to a provided client.

Before you begin, you will need to create a client in the Monzo Development Tools!

let client = MonzoClient(publicKey: "...", privateKey: "...", httpClient: Droplet.client)

A MonzoClient will require a reference to the client object within your Vapor Droplet for networking requests.

Authenticate a user

If the user hasn't authorised your client, then you will need to redirect them to Monzo first.

let client = MonzoClient(publicKey: "...", privateKey: "...", httpClient: Droplet.client)
let uri = client.authorizationURI(redirectUrl: "...", nonce: "...")
// Redirect user to URI

While a nonce is not required, we highly recommend providing a secure and random string to prevent CSRF attacks!

Once the user authorises your client, they will be redirected to the provided URL. You will need to setup a route for this URL, and exchange the token - I provide a helpful function for this!

// Replace this to match the redirectURL
builder.get("oauth/callback") { req in
  // Forward the request, which will in turn validate and exchange the token
  let user = try client.authenticateUser(req, nonce: "...")
}

When authenticating a user, you need to ensure the nonce matches the one used in the previous step.

Load Accounts

Most of the functionality within Monzo is bound to a particular account, obtaining accounts for a user is easy!

let accounts = try user.accounts()

Using undocumented functionality you can also retrieve current accounts, see the undocumented section

Fetch Balance

let balance = try account.balance()

let spentToday = try account.spentToday()

Fetch Transactions

let transactions = try account.transactions()

// If you'd rather not have merchant information, then you can turn it off
let transactions = try account.transactions(merchantInfo: false)

// Pagination support
let transactions = try account.transactions(options: [.limit(20), .since("2015-10-10T23:00:00Z")])

// Once you have an array of transactions, you can load more! (Mutates provided array of transactions)
let foundMore = try transactions.loadMore()

Send Feed Item

The Monzo app is based around a reverse-chronological feed containing various items.

This method allows you to insert your own items into that feed.

Feed items must be of high value to the user, and while the appearance is customisable - care should be taken to ensure it matches the aesthetic of the Monzo mobile apps.

let feedItem = BasicFeedItem(title: "...", imageUrl: "...")

// There are also some optional parameters for further customisation
let feedItem = BasicFeedItem(title: "...",
                            imageUrl: "...",
                            openUrl: "...",
                            body: "...",
                            options: [
                              .backgroundColor("#ABCDEF"),
                              .titleColor("#ABCDEF"),
                              .bodyColor("#ABCDEF")
                            ])

// Send the feed item to a given account
try account.sendFeedItem(feedItem)

Webhooks

Webhooks can be used to receive real-time, push notifications of events in an account.

Currently they are only used for new transactions, see the docs here!

// If you haven't previously loaded webhooks, this will fetch them and then return them
try account.webhooks

// Register Webhook
try account.addWebhook(url: "...")

// Remove Webhook
try webhook.remove()

Attachments

// Register Attachment
let attachment = try transaction.registerAttachment(url: ...)

// Deregister Attachment
try attachment.deregister()

We currently don't support uploading attachments, this is coming soon!

Error Handling

All network requests are designed to throw detailed error messages in the event of something going wrong.

All errors conform to Debuggable allowing you to easily debug what's gone wrong.

If in doubt, please raise an issue on GitHub!

Ping

Taking authentication aside this simple ping test allows you to check that you are able to reach the Monzo API.

If the response is false then I suggest you wait a bit before trying to run further requests!

let success = client.ping()

You can also ping a user, in this instance it will also validate their access token. If autoRefreshToken is enabled, and the user's token has expired then it will be refreshed.

If the response is false then either something is wrong on Monzo's side or the user needs to be authenticated again.

let success = user.ping()

Undocumented

The Monzo API is currently in it's own mode of beta, and is not designed for public use. There is a ticket on the public roadmap currently under "Long Term" which is for the new public API and features such as Sandbox Payments.

Given that, it's fair and understandable that not every endpoint is documented. With that understanding I wanted to enable this framework to have access to all the endpoints I discover but with a clear warning that these are undocumented and might change.

// Retrieve Current Accounts instead of Prepaid Accounts
// If you'd like both types, then you'll need to make two requests
let accounts = try user.accounts(fetchCurrentAccounts: true)

Support

I plan on keeping this framework up-to-date as the public Monzo API evolves. If you have any issues, or questions about this then please raise a GitHub Issue.

When raising issues please try and include as much relevant information as possible including any reproduction steps!

License

I'm releasing this framework under the MIT License.