|
| 1 | +--- |
| 2 | +title: 'API CRUD Operations' |
| 3 | +excerpt: 'This example covers the usage of k6 to test a REST API CRUD operations.' |
| 4 | +--- |
| 5 | + |
| 6 | +The example showcases the testing of CRUD operations on a REST API. |
| 7 | + |
| 8 | +CRUD refers to the basic operations in a database: Create, Read, Update, and Delete. We can map these operations to HTTP methods in REST APIs: |
| 9 | + |
| 10 | +- _Create_: HTTP `POST` operation to create a new resource. |
| 11 | +- _Read_: HTTP `GET` to retrieve a resource. |
| 12 | +- _Update_: HTTP `PUT`or `PATCH` to change an existing resource. |
| 13 | +- _Delete_: HTTP `DELETE` to remove a resource. |
| 14 | + |
| 15 | +## Test steps |
| 16 | + |
| 17 | +In the [setup() stage](/using-k6/test-lifecycle/#setup-and-teardown-stages) we create a user for the [k6 HTTP REST API](https://test-api.k6.io/). We then retrieve and return a bearer token to authenticate the next CRUD requests. |
| 18 | + |
| 19 | +The steps implemented in the [VU stage](/using-k6/test-lifecycle/#the-vu-stage) are as follows: |
| 20 | + |
| 21 | +1. _Create_ a new resource, a "croc". |
| 22 | +2. _Read_ the list of "crocs". |
| 23 | +3. _Update_ the name of the "croc" and _read_ the "croc" to confirm the update operation. |
| 24 | +4. _Delete_ the "croc" resource. |
| 25 | + |
| 26 | +<CodeGroup labels={["api-crud-operations.js"]} lineNumbers={[true]}> |
| 27 | + |
| 28 | +```javascript |
| 29 | +import { describe, expect } from 'https://jslib.k6.io/k6chaijs/4.3.4.3/index.js'; |
| 30 | +import { Httpx } from 'https://jslib.k6.io/httpx/0.1.0/index.js'; |
| 31 | +import { randomIntBetween, randomItem } from "https://jslib.k6.io/k6-utils/1.2.0/index.js"; |
| 32 | + |
| 33 | +export let options = { |
| 34 | + thresholds: { |
| 35 | + checks: [{ |
| 36 | + threshold: 'rate == 1.00', abortOnFail: true, |
| 37 | + }], |
| 38 | + 'http_req_duration': ['p(90)<25000', 'p(95)<30000'], |
| 39 | + 'http_req_duration{name:Create}': ['avg<15000', 'max<25000'], |
| 40 | + }, |
| 41 | + // for the example, let's run only 1 VU with 1 iteration |
| 42 | + vus: 1, |
| 43 | + iterations: 1 |
| 44 | +}; |
| 45 | + |
| 46 | +const USERNAME = `user${randomIntBetween(1, 100000)}@example.com`; // Set your own email; |
| 47 | +const PASSWORD = 'superCroc2019'; |
| 48 | + |
| 49 | +let session = new Httpx({ baseURL: 'https://test-api.k6.io' }); |
| 50 | + |
| 51 | +// Create a random string of given length |
| 52 | +function randomString(length, charset = '') { |
| 53 | + if (!charset) charset = 'abcdefghijklmnopqrstuvwxyz'; |
| 54 | + let res = ''; |
| 55 | + while (length--) res += charset[(Math.random() * charset.length) | 0]; |
| 56 | + return res; |
| 57 | +} |
| 58 | + |
| 59 | +// Authenticate user and retrieve authentication token for the API requests |
| 60 | +export function setup() { |
| 61 | + |
| 62 | + let authToken = null; |
| 63 | + |
| 64 | + describe(`setup - create a test user ${USERNAME}`, () => { |
| 65 | + let resp = session.post(`/user/register/`, { |
| 66 | + first_name: 'Crocodile', |
| 67 | + last_name: 'Owner', |
| 68 | + username: USERNAME, |
| 69 | + password: PASSWORD, |
| 70 | + }); |
| 71 | + |
| 72 | + expect(resp.status, 'User create status').to.equal(201); |
| 73 | + expect(resp).to.have.validJsonBody(); |
| 74 | + }); |
| 75 | + |
| 76 | + describe(`setup - Authenticate the new user ${USERNAME}`, () => { |
| 77 | + let resp = session.post(`/auth/token/login/`, { |
| 78 | + username: USERNAME, |
| 79 | + password: PASSWORD |
| 80 | + }); |
| 81 | + |
| 82 | + expect(resp.status, 'Auth status').to.equal(200); |
| 83 | + expect(resp).to.have.validJsonBody(); |
| 84 | + authToken = resp.json('access'); |
| 85 | + expect(authToken, 'auth token').to.not.be.null; |
| 86 | + }); |
| 87 | + |
| 88 | + return authToken; |
| 89 | +} |
| 90 | + |
| 91 | +export default function (authToken) { |
| 92 | + |
| 93 | + // set the authorization header on the session for the subsequent requests. |
| 94 | + session.addHeader('Authorization', `Bearer ${authToken}`); |
| 95 | + |
| 96 | + describe('01. Create a new crocodile', (t) => { |
| 97 | + let payload = { |
| 98 | + name: `Croc name ${randomString(10)}`, |
| 99 | + sex: randomItem(["M", "F"]), |
| 100 | + date_of_birth: '2023-05-11', |
| 101 | + }; |
| 102 | + |
| 103 | + session.addTag('name', 'Create'); |
| 104 | + let resp = session.post(`/my/crocodiles/`, payload); |
| 105 | + |
| 106 | + expect(resp.status, 'Croc creation status').to.equal(201); |
| 107 | + expect(resp).to.have.validJsonBody(); |
| 108 | + |
| 109 | + session.newCrocId = resp.json('id'); |
| 110 | + }) |
| 111 | + |
| 112 | + describe('02. Fetch private crocs', (t) => { |
| 113 | + |
| 114 | + session.clearTag('name'); |
| 115 | + let resp = session.get('/my/crocodiles/'); |
| 116 | + |
| 117 | + expect(resp.status, 'Fetch croc status').to.equal(200); |
| 118 | + expect(resp).to.have.validJsonBody(); |
| 119 | + expect(resp.json().length, 'number of crocs').to.be.above(0); |
| 120 | + }) |
| 121 | + |
| 122 | + describe('03. Update the croc', (t) => { |
| 123 | + let payload = { |
| 124 | + name: `New croc name ${randomString(10)}`, |
| 125 | + }; |
| 126 | + |
| 127 | + let resp = session.patch(`/my/crocodiles/${session.newCrocId}/`, payload); |
| 128 | + |
| 129 | + expect(resp.status, 'Croc patch status').to.equal(200); |
| 130 | + expect(resp).to.have.validJsonBody(); |
| 131 | + expect(resp.json('name')).to.equal(payload.name); |
| 132 | + |
| 133 | + // read "croc" again to verify the update worked |
| 134 | + let resp1 = session.get(`/my/crocodiles/${session.newCrocId}/`); |
| 135 | + |
| 136 | + expect(resp1.status, 'Croc fetch status').to.equal(200); |
| 137 | + expect(resp1).to.have.validJsonBody(); |
| 138 | + expect(resp1.json('name')).to.equal(payload.name); |
| 139 | + |
| 140 | + }) |
| 141 | + |
| 142 | + describe('04. Delete the croc', (t) => { |
| 143 | + |
| 144 | + let resp = session.delete(`/my/crocodiles/${session.newCrocId}/`); |
| 145 | + |
| 146 | + expect(resp.status, 'Croc delete status').to.equal(204); |
| 147 | + }); |
| 148 | +} |
| 149 | +``` |
| 150 | + |
| 151 | +</CodeGroup> |
0 commit comments