Tuesday, March 29, 2016

Publish a Haskell package in Hackage

Haskell being in the 38th position in the Programming Community Index, it has an immense number of packages providing a variety of functionalities for its developers. You can find the full list of Haskell packages in here. Even though, there are such a huge number of packages many new packages are added to Hackage frequently. 

First, let's understand what does it mean by 'package' in Haskell. A package is the unit of distribution for the Cabal, which is a system for building and packaging Haskell libraries and programs. Its purpose in life, when installed, is to make available some Haskell modules to be imported into a Haskell program a developer is writing.

Before starting off with package development, you need to understand couple of basic rules and regulations in a Haskell package. The main concern in developing a package is that, it should be light-weighted as much as possible, i.e. the build depends section in the cabal file should contain minimal dependencies to the other packages. And the other main thing, you need to be aware of is the documentation. Use 'Haddock' to build the necessary documentation of your package. Refer to this link to read more on the Haddock usage in your Haskell package.

Now that you have a basic understanding about the Haskell packages, let's get to work! 

First step is to make sure your program compiles without any errors. And then, it provides the expected output when run with the desired input parameters. 

Then, create a comprehensive cabal file for your package. You can create a cabal file for your project by running 'cabal init' in your terminal at the project directory. Once you have the basic structure, fill in the required fields of the cabal file using a text editor. After filling out fields, you can check whether your cabal file is correct by running 'cabal check' in the terminal. If there are any missing fields, this command will point out them to you.

After that, use Haddock to build the necessary documentation for the code. To do this, you can type in 'cabal haddock' in your terminal after navigating to the project directory. This command will output the document coverage of the code and points out the necessary places, which need to be updated.


If you don't have any idea how to create a comprehensive documentation for your package, just take a look at the available packages in Hackage and adapt those documentation styles to your package. 

The next step is to create the tarball of your package content. First get your code, cabal file, README file and put them in a folder with the name package-version. For an example; foo-0.1.3.0. You can read more about the package version policy in Haskell in this link
Since I'm using Windows, I used 7-Zip to create a tarball. Following the instructions in their you can create the tarball for you package.

Then comes the part, where you upload the package to Hackage. In order to upload a package, you must have an account. You have to request an account by filling out the form in this link. Once you have your account, log into your account.

There are 2 package upload scenarios; upload a new package OR upload a new version of an existing package.

Scenario 1: Upload a new package.

You can simply go to the upload link in your account, and click on 'Upload a package' leading you here. You can upload you tarball here, and if there are no errors in your tarball structure this will upload the package candidate smoothly. Then go your user-account. Now you can see the uploaded package. If you can't find a link to go to your account, just search your username in the user-accounts list here

Now go to your package and go to 'Maintainer's corner' and click on 'edit package information' which will take you to the publishing page as shown below;















Now you can publish the candidate by clicking on 'Publish candidate', making the package available for the other Haskell developers. 

Scenario 2: Upload a new version of an existing package

In order to do this you should be part of the maintainer group of the package. Given that you are in the maintainer group, you can upload a package candidate following the above steps. But the most important thing to remember is that, you cannot upload the same version number again to Hackage.

There are many resources available in the internet, you can read to get a thorough understanding on the matter. Please do read and understand the procedure before you publish your package, because you can upload a package version once!

Monday, March 21, 2016

Using Basic HTTP Authentication in Haskell

I have recently developed a Haskell library to interact with the Mailchimp JSON API version 2.0. This is the blog post regarding the implementation of the said library. At the end of the blog post I stated, that I will try and update the library to support the version 3.0 of the JSON API. Since the version 2.0 is deprecated long ago and I had some free time in hand, I decided to develop the library to work with version 3.0 API calls. To read further more about the version 3.0 refer to this link.

The major difference in version 3.0 API from the version 2.0 API you need to know in developing the library is that, the removal of API Key from the request body and introducing HTTP Basic Auth in addition to OAuth2. In this implementation, I have used Basic HTTP Auth imported from 'Network.HTTP.Conduit' module in 'http-conduit' package. For further reading on the differences between the two Mailchimp API versions, please follow this link.

The major component in developing the library for version 3.0 was to integrate Basic HTTP authentication with the API calls.  In this post, I'll take you through the implementation of Basic HTTP Auth in the library.

There are 2 basic HTTP requests we need to perform in this library. They are GET and POST requests. For GET requests, the request body is empty while for POST requests we need to send data along with the request. I have implemented 2 separate methods to perform these requests in the library. 

The POST requests in Mailchimp JSON API version 3.0 looks as follows;

    curl --request POST \
  --url 'https://dc.api.mailchimp.com/3.0/campaigns' \
  --user 'anystring:apikey' \
  --header 'content-type:application/json' \
  --data '{"recipients":{"list_id":"et43235dg"},   "type":"regular","settings":{"subject_line":"this is the subject","reply_to":"reply@gmail.com","from_name":"from Mailchimp"}}' \
  --inlcude

So there are two parts for the HTTP request, i.e. authenticate the user and send the json data to the given URL. I used the the 'applyBasicAuth' function in the 'Network.HTTP.Conduit' module. The type definition for this function is as follows;

applyBasicAuth :: ByteString -> ByteString -> Request -> Request

The parameters are passed as 'applyBasicAuth 'username' 'apiKey' $ fromJust $ parseUrl url'Here, what 'applyBasicAuth' function does is attach a Basic Auth Header to the given Request.

In Mailchimp the username for the HTTP authentication is 'anystring', so I have hard-coded it within the functions.

Then we inject the json data to the request body of the resulting Request and the HTTP method to POST. Finally using 'httpLbs' method in 'Network.HTTP.Conduit' module we perform the action we intended. The full code snippet for this function is as follows;



For HTTP GET, the format of the request specified in Mailchimp JSON API version 3.0 is as follows;

    curl --request GET \
  --url 'https://dc.api.mailchimp.com/3.0/lists' \
  --user 'anystring:apikey'

This request retrieves data for all fields regarding each mailing list in the given account. But, if you want to receive only a couple of fields you can specify them in the request. To receive only the list ID and name for each list in the account, the request can be modified as follows;


    curl --request GET \
  --url 'https://dc.api.mailchimp.com/3.0/lists?fields=lists.id,lists.name' \
  --user 'anystring:apikey'

For the GET requests, what I have done is; remove json data injection for the initial request and setting the HTTP method as GET instead of POST. So the function to process HTTP GET request is as follows;



You can get the full program from my GitHub repository. I hope this post will be helpful for you!! Enjoy :)