Skip to content

Commit 574b760

Browse files
committed
Add test
1 parent 47c182f commit 574b760

File tree

10 files changed

+278
-90
lines changed

10 files changed

+278
-90
lines changed

.forgejo/workflows/ci.yml

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: 'CI'
2+
3+
on:
4+
push:
5+
branches:
6+
- 'main'
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
runs-on: docker
12+
13+
strategy:
14+
matrix:
15+
lisp:
16+
- sbcl-bin
17+
18+
steps:
19+
- uses: actions/checkout@v4
20+
21+
- name: Restore cache
22+
id: restore-cache
23+
uses: actions/cache/restore@v4
24+
with:
25+
path: |
26+
~/.roswell
27+
/usr/local/bin/ros
28+
/usr/local/etc/roswell/
29+
qlfile
30+
qlfile.lock
31+
.qlot
32+
~/.cache/common-lisp/
33+
key: roswell-${{ runner.os }}-${{ matrix.lisp }}-${{ hashFiles('qlfile', 'qlfile.lock', '*.asd') }}
34+
35+
- name: Install Roswell
36+
if: steps.restore-cache.outputs.cache-hit != 'true'
37+
env:
38+
LISP: ${{ matrix.lisp }}
39+
run: |
40+
curl -L https://raw.githubusercontent.com/roswell/roswell/master/scripts/install-for-ci.sh | sh
41+
42+
- name: Install Qlot
43+
if: steps.restore-cache.outputs.cache-hit != 'true'
44+
run: |
45+
ros install fukamachi/qlot
46+
47+
- name: Install dependencies
48+
if: steps.restore-cache.outputs.cache-hit != 'true'
49+
run: |
50+
PATH="~/.roswell/bin:$PATH"
51+
qlot install
52+
qlot exec ros install microcms
53+
54+
- name: Save cache
55+
id: save-cache
56+
uses: actions/cache/save@v4
57+
if: steps.restore-cache.outputs.cache-hit != 'true'
58+
with:
59+
path: |
60+
~/.roswell
61+
/usr/local/bin/ros
62+
/usr/local/etc/roswell/
63+
qlfile
64+
qlfile.lock
65+
.qlot
66+
~/.cache/common-lisp/
67+
key: ${{ steps.restore-cache.outputs.cache-primary-key }}
68+
69+
- name: Run tests
70+
run: .qlot/bin/rove microcms.asd

.github/workflows/ci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: 'CI'
2+
3+
on:
4+
push:
5+
branches:
6+
- 'main'
7+
pull_request:
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
lisp:
16+
- sbcl-bin
17+
- ccl-bin
18+
19+
env:
20+
LISP: ${{ matrix.lisp }}
21+
22+
steps:
23+
- uses: actions/checkout@v4
24+
- uses: 40ants/setup-lisp@v4
25+
with:
26+
asdf-system: microcms
27+
- uses: 40ants/run-tests@v2
28+
with:
29+
asdf-system: microcms

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ Before making API requests, set your API key and service domain:
1717

1818
Use `define-list-client` macro to define functions for list-type content.
1919

20+
`query` and `content` must be provided as property list (plist), with keys written in kebab-case (e.g., `:draft-key`).
21+
The JSON response from the microCMS API are automatically converted into plist, with keys transformed from camelCase to kebab-case.
22+
2023
```lisp
2124
(microcms:define-list-client article)
2225
```
@@ -30,8 +33,6 @@ This will generate the following functions:
3033
| `update-article` | (`id`, `content`) | Update an existing article by its ID with new content. |
3134
| `delete-article` | (`id`) | Delete an article by its ID. |
3235

33-
Note: query arguments should be provided as a property list (plist), where keys use kebab-case (e.g., `:draft-key`).
34-
3536
### Object Type Endpoint
3637

3738
Use `define-object-client` macro to define functions for object-type content.

microcms-test.asd

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
(defsystem "microcms-test"
2+
:class :package-inferred-system
3+
:pathname "tests"
4+
:depends-on ("rove"
5+
"microcms-test/client")
6+
:perform (test-op (o c) (symbol-call :rove :run c :style :dot)))

microcms.asd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
:license "MIT"
66
:class :package-inferred-system
77
:pathname "src"
8-
:depends-on ("microcms/main"))
8+
:depends-on ("microcms/main")
9+
:in-order-to ((test-op (test-op "microcms-test"))))

qlfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,5 @@ ql dexador
33
ql jzon
44
ql quri
55
ql kebab
6+
git rove https://github.com/fukamachi/rove
7+
git dissect https://github.com/Shinmera/dissect

qlfile.lock

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,11 @@
2222
(:class qlot/source/ql:source-ql
2323
:initargs (:%version :latest)
2424
:version "ql-2015-06-08"))
25+
("rove" .
26+
(:class qlot/source/git:source-git
27+
:initargs (:remote-url "https://github.com/fukamachi/rove")
28+
:version "git-9868028edf511da5fe61355881af9f4c35f051df"))
29+
("dissect" .
30+
(:class qlot/source/git:source-git
31+
:initargs (:remote-url "https://github.com/Shinmera/dissect")
32+
:version "git-a70cabcd748cf7c041196efd711e2dcca2bbbb2c"))

src/client.lisp

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
(defpackage #:microcms/client
2+
(:use #:cl)
3+
(:import-from #:alexandria
4+
#:remove-from-plist
5+
#:symbolicate
6+
#:alist-hash-table
7+
#:hash-table-alist
8+
#:make-keyword)
9+
(:import-from #:com.inuoe.jzon
10+
#:stringify
11+
#:parse)
12+
(:import-from #:dexador
13+
#:request
14+
#:http-request-failed
15+
#:response-status)
16+
(:import-from #:quri
17+
#:make-uri
18+
#:render-uri)
19+
(:import-from #:kebab
20+
#:to-camel-case
21+
#:to-kebab-case)
22+
(:export #:*api-key*
23+
#:*service-domain*
24+
#:define-list-client
25+
#:define-object-client
26+
#:%build-uri
27+
#:%build-query
28+
#:%build-content
29+
#:%parse-response))
30+
(in-package #:microcms/client)
31+
32+
(defparameter *api-key* nil)
33+
(defparameter *service-domain* nil)
34+
35+
(defun %request (method endpoint &key path query content)
36+
(or *service-domain* (error "microcms:*service-domain* is not configured."))
37+
(or *api-key* (error "microcms:*api-key* is not configured."))
38+
(handler-case
39+
(multiple-value-bind (res-body status res-headers)
40+
(request (%build-uri endpoint :path path :query query)
41+
:method method
42+
:headers `(("X-MICROCMS-API-KEY" . ,*api-key*)
43+
("Content-Type" . "application/json"))
44+
:content (%build-content content)
45+
:force-binary nil)
46+
(format t "microCMS status: ~D~%" status)
47+
(when (and (stringp res-body)
48+
(search "application/json" (gethash "content-type" res-headers)))
49+
(%parse-response res-body)))
50+
(http-request-failed (e)
51+
(format *error-output* "microCMS status: ~D~%" (response-status e)))))
52+
53+
(defun %build-uri (endpoint &key path query)
54+
(render-uri (make-uri :scheme "https"
55+
:host (format nil "~A.microcms.io" *service-domain*)
56+
:path (format nil "/api/v1/~A~@[/~A~]" endpoint path)
57+
:query (%build-query query))))
58+
59+
(defun %kebab-case-plist->camel-case-alist (plist)
60+
(loop :for (key val) :on plist :by #'cddr
61+
:collect (cons (to-camel-case (symbol-name key)) val)))
62+
63+
(defun %camel-case-hash-table->kebab-case-plist (hash-table)
64+
(loop :for (key . val) :in (hash-table-alist hash-table)
65+
:append (list (make-keyword (string-upcase (to-kebab-case key))) val)))
66+
67+
(defun %build-query (query)
68+
(%kebab-case-plist->camel-case-alist query))
69+
70+
(defun %build-content (content)
71+
(and content (stringify (alist-hash-table (%kebab-case-plist->camel-case-alist content)))))
72+
73+
(defun %parse-response (body)
74+
(%camel-case-hash-table->kebab-case-plist (parse body)))
75+
76+
(defmacro define-list-client (endpoint)
77+
(let ((str-endpoint (string-downcase (string endpoint)))
78+
(get-list (symbolicate 'get- endpoint '-list))
79+
(get-detail (symbolicate 'get- endpoint '-detail))
80+
(create (symbolicate 'create- endpoint))
81+
(update (symbolicate 'update- endpoint))
82+
(delete (symbolicate 'delete- endpoint)))
83+
`(list
84+
(defun ,get-list (&key query)
85+
(%request :get ,str-endpoint :query query))
86+
(defun ,get-detail (id &key query)
87+
(%request :get ,str-endpoint :path id :query query))
88+
(defun ,create (content &key query)
89+
(let ((id (getf content :id)))
90+
(%request (if id :put :post)
91+
,str-endpoint
92+
:path id
93+
:query query
94+
:content (remove-from-plist content :id))))
95+
(defun ,update (id content)
96+
(%request :patch ,str-endpoint :path id :content content))
97+
(defun ,delete (id)
98+
(%request :delete ,str-endpoint :path id)))))
99+
100+
(defmacro define-object-client (endpoint)
101+
(let ((str-endpoint (string-downcase (string endpoint)))
102+
(get-object (symbolicate 'get- endpoint '-object))
103+
(update (symbolicate 'update- endpoint)))
104+
`(list
105+
(defun ,get-object (&key query)
106+
(%request :get ,str-endpoint :query query))
107+
(defun ,update (content)
108+
(%request :patch ,str-endpoint :content content)))))

src/main.lisp

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,9 @@
1-
(defpackage #:microcms
1+
(uiop:define-package :microcms
22
(:nicknames #:microcms/main)
3-
(:use #:cl)
4-
(:import-from #:alexandria
5-
#:remove-from-plist
6-
#:symbolicate
7-
#:plist-hash-table)
8-
(:import-from #:com.inuoe.jzon
9-
#:stringify
10-
#:parse)
11-
(:import-from #:dexador
12-
#:request
13-
#:http-request-failed
14-
#:response-status)
15-
(:import-from #:quri
16-
#:make-uri
17-
#:render-uri)
18-
(:import-from #:kebab
19-
#:to-camel-case)
3+
(:use #:cl
4+
#:microcms/client)
205
(:export #:*api-key*
216
#:*service-domain*
227
#:define-list-client
238
#:define-object-client))
24-
(in-package #:microcms)
25-
26-
(defparameter *api-key* nil)
27-
(defparameter *service-domain* nil)
28-
29-
(defun %request (method endpoint &key path query content)
30-
(or *service-domain* (error "microcms:*service-domain* is not configured."))
31-
(or *api-key* (error "microcms:*api-key* is not configured."))
32-
(handler-case
33-
(multiple-value-bind (res-body status res-headers)
34-
(request (%build-uri endpoint :path path :query query)
35-
:method method
36-
:headers `(("X-MICROCMS-API-KEY" . ,*api-key*)
37-
("Content-Type" . "application/json"))
38-
:content (%build-content content)
39-
:force-binary nil)
40-
(format t "microCMS status: ~D~%" status)
41-
(when (and (stringp res-body)
42-
(search "application/json" (gethash "content-type" res-headers)))
43-
(parse res-body)))
44-
(http-request-failed (e)
45-
(format *error-output* "microCMS status: ~D~%" (response-status e)))))
46-
47-
(defun %build-uri (endpoint &key path query)
48-
(render-uri (make-uri :scheme "https"
49-
:host (format nil "~A.microcms.io" *service-domain*)
50-
:path (format nil "/api/v1/~A~@[/~A~]" endpoint path)
51-
:query (%build-query query))))
52-
53-
(defun %build-query (query)
54-
(loop :for (key val) :on query :by #'cddr
55-
:collect (cons (to-camel-case (symbol-name key)) val)))
56-
57-
(defun %build-content (content)
58-
(and content (stringify (plist-hash-table content))))
59-
60-
(defmacro define-list-client (endpoint)
61-
(let ((str-endpoint (string-downcase (string endpoint)))
62-
(get-list (symbolicate 'get- endpoint '-list))
63-
(get-detail (symbolicate 'get- endpoint '-detail))
64-
(create (symbolicate 'create- endpoint))
65-
(update (symbolicate 'update- endpoint))
66-
(delete (symbolicate 'delete- endpoint)))
67-
`(list
68-
(defun ,get-list (&key query)
69-
(%request :get ,str-endpoint :query query))
70-
(defun ,get-detail (id &key query)
71-
(%request :get ,str-endpoint :path id :query query))
72-
(defun ,create (content &key query)
73-
(let ((id (getf content :|id|)))
74-
(%request (if id :put :post)
75-
,str-endpoint
76-
:path id
77-
:query query
78-
:content (remove-from-plist content :|id|))))
79-
(defun ,update (id content)
80-
(%request :patch ,str-endpoint :path id :content content))
81-
(defun ,delete (id)
82-
(%request :delete ,str-endpoint :path id)))))
83-
84-
(defmacro define-object-client (endpoint)
85-
(let ((str-endpoint (string-downcase (string endpoint)))
86-
(get-object (symbolicate 'get- endpoint '-object))
87-
(update (symbolicate 'update- endpoint)))
88-
`(list
89-
(defun ,get-object (&key query)
90-
(%request :get ,str-endpoint :query query))
91-
(defun ,update (content)
92-
(%request :patch ,str-endpoint :content content)))))
9+
(in-package :microcms)

0 commit comments

Comments
 (0)