## 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 ![](https://i.imgur.com/XWys5Th.png) --- ## 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 ![](https://i.imgur.com/pKVFcSw.png) --- ## 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> ![](https://i.imgur.com/NmRk0Ae.gif) --- ## Intellisense <template> ![](https://i.imgur.com/83unmkE.gif) --- ## Spec changed? (status property was removed) ```yaml= Todo: type: object properties: id: type: integer title: type: string ``` --- ![](https://i.imgur.com/C28UUh9.png) --- ## 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}]"}
    724 views