Open9

42APIと戯れる

だいだいだいだい

Getting startedしてみる

https://api.intra.42.fr/apidoc/guides/getting_started

applicationの作成

42APIを使用するにはまずここからapplicationを作成する必要がある。(当たり前だけど42intraへのログインが必要)

設定項目は以下で埋めてみる

UIDとSecretの取得

applicationが作成されるとUIDとSecretが作成されるので、.envに保存しておく。

.env
FTAPI_UID=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
FTAPI_SECRET=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

Access Tokenの取得

curlでAccess Tokenを取得する

$ source .env
$ curl -X POST --data "grant_type=client_credentials&client_id=$FTAPI_UID&client_secret=$FTAPI_SECRET" https://api.intra.42.fr/oauth/token | jq
{
  "access_token": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
  "token_type": "bearer",
  "expires_in": 7200,
  "scope": "public",
  "created_at": 1632393654
}

Userの取得

取得したAccess Tokenを使ってdnakanoさんの情報を取得してみる。(docs

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" https://api.intra.42.fr/v2/users/dnakano | jq  
{
  "id": 76694,
  "email": "dnakano@student.42tokyo.jp",
  "login": "dnakano",
...
だいだいだいだい

OAuth2を利用した認証フローを試してみる

https://api.intra.42.fr/apidoc/guides/web_application_flow

Web Application Flow

Web Application Flowに沿って認可する際には、42APIの認可URIへユーザをリダイレクトさせる。

※ Web Application Flowについてはこれが分かりやすかった。
https://qiita.com/naoya_matsuda/items/67a5a0fb4f50ac1e30c1

認可URI

Base URIのhttps://api.intra.42.fr/oauth/authorizeにクエリパラメータを付加して生成する。以下は例。

https://api.intra.42.fr/oauth/authorize?client_id=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef&redirect_uri=https://42tokyo.jp&response_type=code&scope=public&state=qwerty

クエリパラメータに関しては以下のとおり(詳しくはdocsを参照のこと)

  • client_id: applicationのUID(最初にここで作成したやつ)
  • redirect_uri: 認可後にリダイレクトする先のURI
  • response_type: 帰ってくるtokenのtype。codeを指定すればOK。
  • scope: 帰ってくるtokenで何にアクセスできるかを指定(application作成時で指定したscopeと同じ粒度で指定できると思われる)
  • state: CSRF対策のための文字列(本番では長くて予測できない文字列を使用すること!)

認可URIにアクセスすると、よく見る認証ページにリダイレクトされる。

login page
auth page

認証を許可すれば、redirect_uriで指定したページへリダイレクトされる。この際、以下のようにクエリパラメータにcodestateが付加される。

https://42tokyo.jp/?code=abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789&state=qwerty

codeを利用することで、42APIのリソースにアクセスできる。また、stateはCSRF対策としてアプリケーション側で指定したstateかどうか検証すること。

codeを使ってapiを叩く

まず、取得したcodeからaccess_tokenを取得する。
https://api.intra.42.fr/oauth/tokenにPOSTリクエストし、access_tokensを取得する。

$ curl -F grant_type=authorization_code \
-F client_id=$FTAPI_UID \
-F client_secret=$FTAPI_SECRET \
-F code=abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789 \
-F redirect_uri=https://42tokyo.jp \
-X POST https://api.intra.42.fr/oauth/token | jq
{
  "access_token": "56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234",
  "token_type": "bearer",
  "expires_in": 7200,
  "refresh_token": "def0123456789abcdef0123456789abcdef0123456789abcdef0123456789abc",
  "scope": "public",
  "created_at": 1632404312
}

取得したaccess_tokenを使って取得する。

$ curl -H "Authorization: Bearer 56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234" https://api.intra.42.fr/v2/me | jq
{
  "id": 76694,
  "email": "dnakano@student.42tokyo.jp",
  "login": "dnakano",
...
だいだいだいだい

GoでToken取得するコード

package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"net/url"
	"strings"
)

type OauthTokenResponse struct {
	AccessToken string `json:"access_token"`
	TokenType   string `json:"token_type"`
	ExpiresIn   int    `json:"expires_in"`
	Scope       string `json:"scope"`
	CreatedAt   int    `json:"created_at"`
}

func main() {
	value := url.Values{}
	value.Set("grant_type", "client_credentials")
	value.Set("client_id", "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
	value.Set("client_secret", "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789")

	req, err := http.NewRequest(http.MethodPost, "https://api.intra.42.fr/v2/oauth/token", strings.NewReader(value.Encode()))
	if err != nil {
		panic(err)
	}

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}

	var oauthRes OauthTokenResponse
	err = json.NewDecoder(res.Body).Decode(&oauthRes)
	if err != nil {
		panic(err)
	}

	fmt.Printf("%#v\n", oauthRes)
}
$ go run main.go
main.OauthTokenResponse{AccessToken:"56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234", TokenType:"bearer", ExpiresIn:7200, Scope:"public", CreatedAt:1632548646}
だいだいだいだい

Getting informations about your token

https://api.intra.42.fr/apidoc/guides/getting_started#getting-informations-about-your-token

access_tokenの情報は/oauth/token/infoから見れる。

applicationのuid、secretから取得したトークンの取得例。

$ curl -H "Authorization: Bearer $FTAPI_ACCESS_TOKEN" https://api.intra.42.fr/oauth/token/info | jq
{
  "resource_owner_id": null,
  "scopes": [
    "public"
  ],
  "expires_in_seconds": 7080,
  "application": {
    "uid": "56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234"
  },
  "created_at": 1632613447
}

codeから取得したtoken。resource_owner_idが入る。

$ curl -H "Authorization: Bearer $FTAPI_ACCESS_TOKEN" https://api.intra.42.fr/oauth/token/info | jq
{
  "resource_owner_id": 76694,
  "scopes": [
    "public"
  ],
  "expires_in_seconds": 7146,
  "application": {
    "uid": "56789abcdef0123456789abcdef0123456789abcdef0123456789abcdef01234"
  },
  "created_at": 1632617132
}
だいだいだいだい

ページング処理

複数の結果を返すエンドポイントでは、ページングで結果の範囲を指定する。
doc: https://api.intra.42.fr/apidoc/guides/specification#pagination

デフォルトでは1ページ目を30項目読む

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" https://api.intra.42.fr/v2/roles
...(30項目

指定の仕方

ページ数と1ページ当たりの項目数はクエリで指定できる。

page or page[number] : ページ数
per_page or page[size] : ページ当たりの数(最大100)

pageper_pageで指定する場合

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" 'https://api.intra.42.fr/v2/roles?page=4&per_page=2' | jq
[
  {
    "id": 32,
    "name": "42Network",
    "description": "42Network team"
  },
  {
    "id": 31,
    "name": "Project Session Manager",
    "description": "Brobot will send you notification when a ps is updated"
  }
]

page[number]page[size]で指定する場合

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" 'https://api.intra.42.fr/v2/roles?page[number]=4&page[size]=2' | jq
[
  {
    "id": 32,
    "name": "42Network",
    "description": "42Network team"
  },
  {
    "id": 31,
    "name": "Project Session Manager",
    "description": "Brobot will send you notification when a ps is updated"
  }
]

ヘッダ

レスポンスヘッダに以下の情報が入ってくる。

  • link: ページの先頭(first)、最後(last)、前後ページ(prev, next)へのリンク
  • x-per-page: ページ当たりの項目数
  • x-page: 取得したページ数
link: <https://api.intra.42.fr/v2/roles?page=1>; rel="first", <https://api.intra.42.fr/v2/roles?page=3>; rel="prev", <https://api.intra.42.fr/v2/roles?page=17>; rel="last", <https://api.intra.42.fr/v2/roles?page=5>; rel="next"
x-per-page: 2
x-page: 4
x-total: 34
だいだいだいだい

フィルタのかけ方

複数の結果を返すエンドポイントでは、フィルタを指定できる。

クエリパラメタにfilter[フィルタしたい内容]=値を指定する。

以下はtokyoキャンパス(primary_campus_id=26)の生徒一覧を取得する例。

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" -g 'https://api.intra.42.fr/v2/users?filter[primary_campus_id]=26'

なお、存在しないフィルタを指定すると400エラーが返ってくる。

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" -g 'https://api.intra.42.fr/v2/users?filter[hoge]=fuga' | jq
{
  "error": "Filter Error",
  "message": "Attributes hoge doesn't exists or aren't filterables. Available filters are: id, login, email, created_at, updated_at, pool_year, pool_month, kind, status, primary_campus_id, first_name, last_name, alumni?, is_launched?, and staff?"
}

利用できるフィルタは、42apiのdocsに書いてある。
https://api.intra.42.fr/apidoc/2.0/users/index.html

だいだいだいだい

ソートの掛け方

クエリパラメタで。sort=ソートしたい属性 を指定する

idで昇順にソートする例。

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" -g 'https://api.intra.42.fr/v2/users?sort=id'

ソート順を逆にしたい場合は、sort=-ソートしたい属性 のように-をつける。

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" -g 'https://api.intra.42.fr/v2/users?sort=-id'

複数パラメタでソートしたい場合は、,で繋げる。

curl -H "Authorization: Bearer $ACCESS_TOKEN" -g 'https://api.intra.42.fr/v2/users?sort=kind,-login'

ソートできる属性も限られていて、それ以外だと400エラーになる。ソートできる属性はdocs参照のこと。
https://api.intra.42.fr/apidoc/2.0/users/index.html

だいだいだいだい

範囲指定の掛け方

また、クエリパラメタにrange[属性]=最小値,最大値で範囲(range)指定もかけられる。

$ curl -H "Authorization: Bearer $ACCESS_TOKEN" -g 'https://api.intra.42.fr/v2/users?range[pool_year]=2020,2021'

これも、指定できる属性は限られている。Docsの各エンドポイントのページを参照のこと。
https://api.intra.42.fr/apidoc/2.0/users/index.html