## Contract driven Vue components
Esben Kvorning ekv@ucommerce.net
---
## Disclaimer
~~How we build contract driven Vue components~~
:arrow_down:
Contract driven Vue components
---
## The API contract
Declares how to interact with an API.
* Operation URLs
* Operation actions (`GET`, `POST` etc.)
* Operation parameters
* Operation responses
* Etc.
---
## What does it solve?
---
## Reliability issues
Expected:
```json=
{
"name": "John Doe",
"age": 37
}
```
Returned:
```json=
{
"Name": "John Doe",
"Age": "37"
}
```
---
## Transparency issues
What can the consumer do with the API?
---
## Parallelisation issues
Front-end team waiting for back-end team etc.
---
## OpenAPI (OAS)
A standardised interface for RESTful APIs
www.openapis.org
(formerly known as Swagger)
---
## OpenAPI operation
(Simplified)
```yaml=
"/todos":
get:
summary: List all available todos
operationId: listTodos
responses:
'200':
description: Successful operation
content:
application/json:
schema:
type: array
items:
"$ref": "#/components/schemas/Todo"
```
---
## OpenAPI schema
(Simplified)
```yaml=
schemas:
Todo:
type: object
properties:
id:
type: integer
title:
type: string
status:
type: string
enum:
- waiting
- working
- done
```
---
## OpenAPI response
(Simplified)
```yaml=
examples:
default:
value:
- id: 1
title: Tidy up the shed
status: working
- id: 2
title: Paint the kitchen
status: waiting
- id: 3
title: Read a book
status: done
```
---
## Generate documentation
Using tools like Redoc, SwaggerUI etc.
---
## Don't want to write a spec?
It's fine, you can usually generate one from your existing API with tools like Swashbuckle.
---
## Using the spec
OpenAPI spec
:arrow_down:
Mock API
:arrow_down:
Mock library
:arrow_down:
Vue
---
## Mock API
[OpenAPI Backend](https://github.com/anttiviljami/openapi-backend)
```javascript=
import OpenAPIBackend from 'openapi-backend';
const api = new OpenAPIBackend({ definition: './openapi.yml' });
```
---
## Mock library
[Mock Service Worker (MSW)](https://mswjs.io/)
```javascript=
import { setupWorker, rest } from 'msw'
const worker = setupWorker(
rest.get('http://api.example.com/todos', (req, res, ctx) => {
return res(
ctx.delay(200),
ctx.status(200),
ctx.json([
{ "id": 1, "title": "Item 1", "status": "working" },
{ "id": 2, "title": "Item 2", "status": "waiting" },
{ "id": 3, "title": "Item 3", "status": "done" },
])
)
})
)
```
---
## Mocked request

---
## Can we automate it?
---
## Yup!
```javascript=
import { setupWorker } from 'msw'
import { handlers } from '@visma/msw-openapi-backend-integration'
import definition from '../openapi.yml'
export const worker = setupWorker(...handlers({ definition }))
```
---
## What about tests?
---
## Of course!
```javascript=
import { rest } from 'msw'
import { setupServer } from 'msw/node'
import { handlers } from '@visma/msw-openapi-backend-integration'
import definition from '../openapi.yml'
const server = setupServer(...handlers({ definition }))
beforeAll(() => { server.listen() })
afterAll(() => { server.close() })
it('renders the todo list', () => {
// test logic
})
```
---
## And Storybook?
> "Storybook is an open source tool for building UI components and pages in isolation. It streamlines UI development, testing, and documentation."
---
## Most definitely

---
## Can we have types?
---
## Sure!
OpenAPI spec
:arrow_down:
OpenAPI client generator
:arrow_down:
API client
:arrow_down:
Vue
---
## OpenAPI client generator
[OpenAPI Typescript Codegen](https://github.com/ferdikoomen/openapi-typescript-codegen)
```bash=
npx openapi --input ./openapi.yml --output ./api
```
---
## API client
```
api/
├─ core/
├─ models/
│ ├─ Todo.ts
├─ services/
│ ├─ TasksService.ts
├─ index.ts
```
---
## Vue component
```javascript=
<script lang="ts" setup>
import { ref } from 'vue'
import { TasksService, Todo } from '@/api'
const todos = ref<Todo[]>(await TasksService.listTodos())
</script>
```
---
## Intellisense <script>

---
## Intellisense <template>

---
## Spec changed?
(status property was removed)
```yaml=
Todo:
type: object
properties:
id:
type: integer
title:
type: string
```
---

---
## And that's all for now
Thank you for listening :)
---
## Questions?
{"metaMigratedAt":"2023-06-16T10:56:06.988Z","metaMigratedFrom":"YAML","title":"Contract driven Vue components","breaks":true,"slideOptions":"{\"theme\":\"blood\",\"allottedMinutes\":25}","contributors":"[{\"id\":\"e38f2ad9-3bcf-443c-bed9-6df9657c06a6\",\"add\":9619,\"del\":4683}]"}