Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add R API container to dev dependencies script, and consume R API from app #10

Merged
merged 51 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
1587ce4
WIP - front end can talk to R API
david-mears-2 Jul 29, 2024
704d4b7
Add .nvmrc
david-mears-2 Jul 29, 2024
985a75f
Update scripts
david-mears-2 Jul 29, 2024
3c98f7c
Add db:dev:migrate npm command
david-mears-2 Jul 29, 2024
ee643a0
Use utility instead of proxy api for R API; display version numbers
david-mears-2 Jul 30, 2024
18cb9e4
Streamline setup instructions
david-mears-2 Jul 30, 2024
d4c216e
Use composable instead of 'util' for R API consumption
david-mears-2 Jul 30, 2024
e8567db
Change linting rule
david-mears-2 Jul 30, 2024
e8ffe19
wip, I was mid-way through adapting the code to allow mocking for tests
david-mears-2 Jul 31, 2024
7ee6a28
Revert "wip, I was mid-way through adapting the code to allow mocking…
david-mears-2 Jul 31, 2024
d14a0eb
Return to using web app server API to talk to R API
david-mears-2 Jul 31, 2024
7669aa7
Try running Playwright with dependent services
david-mears-2 Aug 1, 2024
f187eeb
Revert "Try running Playwright with dependent services"
david-mears-2 Aug 1, 2024
1897a64
Deduplicate README
david-mears-2 Aug 1, 2024
77e31a4
Log more, for debugging
david-mears-2 Aug 2, 2024
5aa5870
Add ssh
david-mears-2 Aug 2, 2024
234bac2
increase retries and timeout
david-mears-2 Aug 2, 2024
418189f
Copy env vars
david-mears-2 Aug 2, 2024
94612e8
Try using the repo env
david-mears-2 Aug 2, 2024
a978237
Next iter of env var setup
david-mears-2 Aug 2, 2024
b2ce44c
ssh
david-mears-2 Aug 2, 2024
2bff65b
ssh iter
david-mears-2 Aug 2, 2024
fb2bf48
env var iter
david-mears-2 Aug 2, 2024
7f44bc5
Use script for env vars for github actions
david-mears-2 Aug 2, 2024
776d3a8
Run service dependencies
david-mears-2 Aug 2, 2024
1eabcfc
Ensure dependency services can find git branch name on CI environment
david-mears-2 Aug 2, 2024
1c9e574
remove debug
david-mears-2 Aug 2, 2024
276e91e
update tests - add r one
david-mears-2 Aug 2, 2024
76bef3b
Remove flaky low-value e2e test of sidebar behaviour
david-mears-2 Aug 2, 2024
0357db4
Use production mode for playwright web server
david-mears-2 Aug 2, 2024
68a2047
Add testing of Nuxt API endpoints, using external mocking service
david-mears-2 Aug 2, 2024
e1921c8
Test Mockoon is running on CI
david-mears-2 Aug 2, 2024
2c94900
Add timeout to long-running test
david-mears-2 Aug 2, 2024
1a4715e
Increase timeout on long-running test
david-mears-2 Aug 2, 2024
ee66623
Add env var for unit-tests.yml
david-mears-2 Aug 6, 2024
18d6ea1
Remove test timeout
david-mears-2 Aug 6, 2024
11801e2
Remove commented-out earlier test writing attempts
david-mears-2 Aug 6, 2024
871bb3d
Add documentation for Mockoon and how to unit test our API endpoints
david-mears-2 Aug 6, 2024
43d47b0
Fix unit test github action
david-mears-2 Aug 6, 2024
d45d437
Tweaks to unit test
david-mears-2 Aug 6, 2024
c70b3aa
Merge pull request #16 from jameel-institute/friday-pm-playwright
david-mears-2 Aug 6, 2024
4d8f286
Use non-public (server-side only) nuxt config variable
david-mears-2 Aug 6, 2024
54aa577
Update README
david-mears-2 Aug 6, 2024
6e0ed26
Simplify api dir structure
david-mears-2 Aug 6, 2024
1a82a3b
Refactor API to use types, pass on R API status codes/texts
david-mears-2 Aug 7, 2024
a2bfe29
Add more detail to integration test
david-mears-2 Aug 7, 2024
c862e0f
Update .github/workflows/integration-tests.yml
david-mears-2 Aug 8, 2024
5d875f7
Update README.md
david-mears-2 Aug 8, 2024
5de1f22
Update README.md
david-mears-2 Aug 8, 2024
6cfc4bd
Add wrapper for defineEventHandler to handle errors
david-mears-2 Aug 9, 2024
0701f44
Merge branch 'jidea-38-containerisation-r-api' of github.com:jameel-i…
david-mears-2 Aug 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/integration-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
with:
data-file: ./mocks/mockoon.json
port: 8001
- name: Check API server is running
- name: Check mocked R API server is running
run: curl -s http://localhost:8001/mock-smoke
- name: Set environment variables for app
run: scripts/ci/copy-env-vars-to-dot-env-file
Expand Down
15 changes: 7 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ npx nuxi analyze

# Tests

To run unit tests, component tests and integration tests, first start the Mockoon server:
```bash
npx mockoon-cli start --data ./mocks/mockoon.json
```

Then, to run unit tests:
To run unit tests:
```bash
npm run test:unit
# Or with coverage:
npm run test:unit:coverage
```

To run integration tests:
To run integration tests, first start the Mockoon server:
```bash
npx mockoon-cli start --data ./mocks/mockoon.json
```
Then run:
```bash
npm run test:integration
```
Expand All @@ -28,7 +27,7 @@ npm run test:ssr

Run full-stack tests:

1. Stop the Mockoon server
1. Ensure Mockoon server is not running
1. Run:
```bash
npm run test:e2e
Expand Down
2 changes: 1 addition & 1 deletion components/SideBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@

<script lang="ts" setup>
import { CIcon } from "@coreui/icons-vue";
import type { VersionData } from "@/types/apiResponseTypes";
import type { VersionData } from "@/types/daedalusApiResponseTypes";

const { data: versionData } = useFetch("/api/versions") as { data: Ref<VersionData> };
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems likely that this pattern will be repeated a lot, so we'll probably eventually want a generic typs something like

export interface APIResponse<T> {
  data: Ref<T>
}

so then this line would become
const { data: versionData } = useFetch("/api/versions") as APIResponse<VersionData>;

..but then I suspect maybe we'll also eventually have some sort of useAPI which wraps the raw useFetch and just gives back the data you're interested in, and helps with error handling. So probably not one for this PR.

UPDATE: I see below that you've got ServerApiResponse, but I think that refers to responses from the R API?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ServerApiResponse was named to try and distinguish it from the R API, so that'll have to be re-named... if we simply call it ApiResponse might that actually be clearer?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though ServerApiResponse's purpose differs from what you're talking about - ServerApiResponse (well, types extended from it) are to be used inside the API routes to dictate the format of the response's data, rather than to be used wrapping a useFetch.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, exactly. I think probably the response types from the R API (used in the web app backend) and the types from the web app backend (used in the front end) should probably live in different modules, and maybe a "shared" module for ones that happen to be the same, with whatever generic classes are useful in the two contexts. Maybe ServerApiResponse and RApiResponse (I think DaedalusApiResponse would be more correct, but very verbose, and you already have rApi module...)


Expand Down
26 changes: 10 additions & 16 deletions server/api/versions.get.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,13 @@
import { getVersionData } from "@/server/handlers/versions";
import { errorMessage } from "@/server/utils/helpers";
import type { VersionData } from "@/types/apiResponseTypes";
import { defineEventHandlerWithErrors } from "@/server/utils/defineEventHandlerWithErrors";

Check warning on line 2 in server/api/versions.get.ts

View check run for this annotation

Codecov / codecov/patch

server/api/versions.get.ts#L2

Added line #L2 was not covered by tests
import type { VersionDataResponse } from "@/types/daedalusApiResponseTypes";

export default defineEventHandler(async (event): Promise<VersionData> => {
// Delegate to handler function getVersionData so that the logic can be unit-tested.
const versionDataResponse = await getVersionData(event);
export default defineEventHandlerWithErrors(

Check warning on line 5 in server/api/versions.get.ts

View check run for this annotation

Codecov / codecov/patch

server/api/versions.get.ts#L5

Added line #L5 was not covered by tests
// TODO: Consider cacheing this server-side https://nitro.unjs.io/guide/cache
defineEventHandler(async (event): Promise<VersionDataResponse> => {

Check warning on line 7 in server/api/versions.get.ts

View check run for this annotation

Codecov / codecov/patch

server/api/versions.get.ts#L7

Added line #L7 was not covered by tests
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit surprised that you're still invoking defineEventHandler here, since your new custom defineEventHandlerWitErrors already wraps defineEventHandler - do you have one more layer of defineEventHandler than you need?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a way around this, here is the commit: b029800

It's not yet a commit that lives in a PR.

// Delegate to getVersionData so that the logic can be unit-tested.
const versionDataResponse = await getVersionData(event);

Check warning on line 9 in server/api/versions.get.ts

View check run for this annotation

Codecov / codecov/patch

server/api/versions.get.ts#L9

Added line #L9 was not covered by tests

if (versionDataResponse.errors || !versionDataResponse.data) {
throw createError({
statusCode: versionDataResponse.statusCode,
statusMessage: versionDataResponse.statusText,
message: errorMessage(versionDataResponse.errors),
data: versionDataResponse.errors,
});
} else {
return versionDataResponse.data;
}
});
return versionDataResponse;
}),
);

Check warning on line 13 in server/api/versions.get.ts

View check run for this annotation

Codecov / codecov/patch

server/api/versions.get.ts#L11-L13

Added lines #L11 - L13 were not covered by tests
2 changes: 1 addition & 1 deletion server/handlers/versions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { EventHandlerRequest, H3Event } from "h3";
import { fetchRApi } from "@/server/utils/rApi";
import packageJson from "@/package.json";
import type { VersionData, VersionDataResponse } from "@/types/apiResponseTypes";
import type { VersionData, VersionDataResponse } from "@/types/daedalusApiResponseTypes";

const rApiVersionEndpoint = "/";

Expand Down
20 changes: 20 additions & 0 deletions server/utils/defineEventHandlerWithErrors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { EventHandler, EventHandlerRequest } from "h3";
import type { ApiResponse } from "@/types/daedalusApiResponseTypes";

export const defineEventHandlerWithErrors = <T extends EventHandlerRequest, D>(
handler: EventHandler<T, D>,

Check warning on line 5 in server/utils/defineEventHandlerWithErrors.ts

View check run for this annotation

Codecov / codecov/patch

server/utils/defineEventHandlerWithErrors.ts#L4-L5

Added lines #L4 - L5 were not covered by tests
): EventHandler<T, D> =>
defineEventHandler<T>(async (event) => {
const response = await handler(event) as ApiResponse;

Check warning on line 8 in server/utils/defineEventHandlerWithErrors.ts

View check run for this annotation

Codecov / codecov/patch

server/utils/defineEventHandlerWithErrors.ts#L7-L8

Added lines #L7 - L8 were not covered by tests

if (response.errors || !response.data) {
throw createError({
statusCode: response.statusCode,
statusMessage: response.statusText,
message: errorMessage(response.errors),
data: response.errors,
});
} else {
return response.data;
}
});

Check warning on line 20 in server/utils/defineEventHandlerWithErrors.ts

View check run for this annotation

Codecov / codecov/patch

server/utils/defineEventHandlerWithErrors.ts#L10-L20

Added lines #L10 - L20 were not covered by tests
2 changes: 1 addition & 1 deletion server/utils/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { ApiError } from "@/types/apiResponseTypes";
import type { ApiError } from "@/types/daedalusApiResponseTypes";

// Convert list of error objects to string
export const errorMessage = (errors: Array<ApiError> | null) => {
return errors?.map((apiError) => {
return [apiError.error, apiError.detail].join(": ");
}).join(", ");
};

Check warning on line 8 in server/utils/helpers.ts

View check run for this annotation

Codecov / codecov/patch

server/utils/helpers.ts#L4-L8

Added lines #L4 - L8 were not covered by tests
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ export interface ApiError {
error: string
detail: string
}

interface ServerApiResponse<T extends object> {
export interface ApiResponse<T extends object = object> {
statusText: string
statusCode: number
errors: Array<ApiError> | null
Expand All @@ -18,4 +17,4 @@ export interface VersionData {
daedalusWebApp: string
}

export interface VersionDataResponse extends ServerApiResponse<VersionData> { }
export interface VersionDataResponse extends ApiResponse<VersionData> { }
Loading