注目の記事

[Apiary]Markdownで始めるAPI開発とAPIドキュメント作成

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

APIを作るとき

みなさん、毎日API使ってますか?私は、ワンライナーでAPIをコールすることにハマっています。さて、いつも使っているAPIを作る側になったとき、どのように設計していますでしょうか?また、作ったAPIをどのように使ってもらっていますか?そんな疑問に応えるサービスがApiaryです。

Apiaryとは?

Apiaryは、REST APIをサクッと書けるサービスです。また、APIドキュメントも生成してくれます。モックサーバも提供してくれます。API利用サンプルコードも作ってくれます。うん、使わないって選択肢は無いですねw。

無料登録すると早速使えるようになります。チームでプライベートなAPI開発をしたければ有料プランを選択してください。

screenshot 2015-02-18 10.00.41

API開発の流れ

API開発の流れは、まずはじめにMarkdown形式でドキュメントを書きます。既にサンプルがあるのでこれを使ってみましょう。

screenshot 2015-02-18 10.02.22

右側にドキュメントのプレビューが現れましたね。さっそく使ってみましょう。List all Notesを選択します。すると、APIのモックを利用できる画面が出てきます。

screenshot 2015-02-18 11.37.35

ドキュメントを書いただけなのにAPIを実行できました!

screenshot 2015-02-18 11.38.37

CORS設定

API利用時にCORS(クロスドメインアクセス)をしたいときがありますよね。Apiaryの設定画面でON/OFF可能です。

サンプルコードの利用

できあがったモックAPIサーバを利用するサンプルコードも自動生成されます。これはありがたいですね!

cURL

curl --include \
'http://private-ee96-satoshi7.apiary-mock.com/notes'

Java

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("http://private-ee96-satoshi7.apiary-mock.com")
  .path("/notes")
  .request(MediaType.TEXT_PLAIN_TYPE)
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

JavaScript

var Request = new XMLHttpRequest();

Request.open('GET', 'http://private-ee96-satoshi7.apiary-mock.com/notes');

Request.onreadystatechange = function () {
  if (this.readyState === 4) {
    console.log('Status:', this.status);
    console.log('Headers:', this.getAllResponseHeaders());
    console.log('Body:', this.responseText);
  }
};

Request.send(JSON.stringify(body));

Node.js

var request = require('request');

request('http://private-ee96-satoshi7.apiary-mock.com/notes', function (error, response, body) {
  console.log('Status:', response.statusCode);
  console.log('Headers:', JSON.stringify(response.headers));
  console.log('Response:', body);
});

Perl

require LWP::UserAgent;

my $ua   = LWP::UserAgent->new;

my $response = $ua->get("http://private-ee96-satoshi7.apiary-mock.com/notes");

print $response->as_string;

Python

from urllib2 import Request, urlopen

request = Request('http://private-ee96-satoshi7.apiary-mock.com/notes')

response_body = urlopen(request).read()
print response_body

PHP

<?php
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "http://private-ee96-satoshi7.apiary-mock.com/notes");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);

$response = curl_exec($ch);
curl_close($ch);

var_dump($response);
[/code]

<h4>Ruby</h4>


<h4>Go</h4>

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	client := &http.Client{}

	req, _ := http.NewRequest("GET", "http://private-ee96-satoshi7.apiary-mock.com/notes", nil)

	resp, err := client.Do(req)

	if err != nil {
		fmt.Println("Errored when sending request to the server")
		return
	}

	defer resp.Body.Close()
	resp_body, _ := ioutil.ReadAll(resp.Body)

	fmt.Println(resp.Status)
	fmt.Println(string(resp_body))
}

C#

using System;
using System.Net.Http;

var baseAddress = new Uri("http://private-ee96-satoshi7.apiary-mock.com/");

using (var httpClient = new HttpClient{ BaseAddress = baseAddress })
{

  using(var response = await httpClient.GetAsync("notes"))
  {
 
        string responseData = await response.Content.ReadAsStringAsync();
  }
}

VisualBasic

Dim request = TryCast(System.Net.WebRequest.Create("http://private-ee96-satoshi7.apiary-mock.com/notes"), System.Net.HttpWebRequest)

request.Method = "GET"

request.ContentLength = 0
Dim responseContent As String
Using response = TryCast(request.GetResponse(), System.Net.HttpWebResponse)
  Using reader = New System.IO.StreamReader(response.GetResponseStream())
    responseContent = reader.ReadToEnd()
  End Using
End Using

Groovy

import groovyx.net.http.RESTClient
import static groovyx.net.http.ContentType.JSON
import groovy.json.JsonSlurper
import groovy.json.JsonOutput

@Grab (group = 'org.codehaus.groovy.modules.http-builder', module = 'http-builder', version = '0.5.0')
def client = new RESTClient("http://private-ee96-satoshi7.apiary-mock.com")

response = client.get( path : "/notes")

println("Status:" + response.status)

if (response.data) {
  println("Content Type: " + response.contentType)
  println("Body:\n" + JsonOutput.prettyPrint(JsonOutput.toJson(response.data)))
}

Objective-C

NSURL *URL = [NSURL URLWithString:@"http://private-ee96-satoshi7.apiary-mock.com/notes"];

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
[request setHTTPMethod:@"GET"];

NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request
                                        completionHandler:
                              ^(NSData *data, NSURLResponse *response, NSError *error) {

                                  if (error) {
                                      // Handle error...
                                      return;
                                  }

                                  if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                      NSLog(@"Response HTTP Status code: %ld\n", (long)[(NSHTTPURLResponse *)response statusCode]);
                                      NSLog(@"Response HTTP Headers:\n%@\n", [(NSHTTPURLResponse *)response allHeaderFields]);
                                  }

                                  NSString* body = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                                  NSLog(@"Response Body:\n%@\n", body);
                              }];
[task resume];

Swift

let url = NSURL(string: "http://private-ee96-satoshi7.apiary-mock.com/notes")!
let request = NSMutableURLRequest(URL: url)

let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request) { (data: NSData!, response: NSURLResponse!, error: NSError!) in

    if error != nil {
        // Handle error...
        return
    }

    println(error)
    println(response)
    println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

Swift Representor

import Alamofire
import Representor

let blueprint = Blueprint(named: "blueprint.json", bundle: nil)
let baseURL = NSURL(string: "http://private-ee96-satoshi7.apiary-mock.com/")

if let transition = blueprint?.transition("Notes Collection", action: "List all Notes") {
  request(baseURL, transition, parameters:parameters)
    .response { (request, response, data, error) in
      // Handle the response
    }
}

まとめ

Markdownを書いたらAPIとドキュメントが出来上がっていますので、クライアントサイドとサーバーサイドで後からごにょごにょ繋げるのではなく、先にAPI(アプリケーションをプログラミングするときに使うインタフェース)部分を決めることで、開発は大分楽になるのではないでしょうか。

参照情報

Apiary