{"id":19664395,"url":"https://github.com/beda-software/faq","last_synced_at":"2026-03-19T11:01:34.181Z","repository":{"id":54550261,"uuid":"243725604","full_name":"beda-software/FAQ","owner":"beda-software","description":null,"archived":false,"fork":false,"pushed_at":"2021-11-29T16:51:27.000Z","size":123,"stargazers_count":3,"open_issues_count":6,"forks_count":6,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-03-13T07:03:13.302Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/beda-software.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-02-28T09:31:06.000Z","updated_at":"2023-04-19T21:06:13.000Z","dependencies_parsed_at":"2022-08-13T19:20:49.526Z","dependency_job_id":null,"html_url":"https://github.com/beda-software/FAQ","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/beda-software/FAQ","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2FFAQ","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2FFAQ/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2FFAQ/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2FFAQ/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/beda-software","download_url":"https://codeload.github.com/beda-software/FAQ/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/beda-software%2FFAQ/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29995912,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-11T16:17:43.034Z","updated_at":"2026-03-02T08:32:45.931Z","avatar_url":"https://github.com/beda-software.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Contents\n- [Best practicies](#best-practicies)\n  - [React Native](#react-native)\n  - [Typescript](#typescript)\n  - [Backend Python](#backend-python)\n  - [Aidbox](#aidbox)\n- [BS video library (meetup records)](video-library.md)\n- [Learning materials](learning_materials.md)\n- [SNOMED and Snowstorm](snowstorm_snomed.md)\n- [React Native tips](react-native-tips.md)\n- [kubectl/k8s cheat sheet](k8s.md)\n- Tutorials\n  - [Setting up GitLab runner on AWS EC2](aws-ec2-gitlab-runner.md)\n\n# Best practicies\n\n## React Native\n\n#### Debugging network requests in react-native\n```javascript\n// To see all the requests in the chrome Dev tools in the network tab.\nXMLHttpRequest = GLOBAL.originalXMLHttpRequest ?\n    GLOBAL.originalXMLHttpRequest :\n    GLOBAL.XMLHttpRequest;\n```\nDon't forget to remove it before pushing!\n\n#### Open link in a running simulator\n\n```sh\nxcrun simctl openurl booted link-goes-here\n```\n#### Jest testing\n\n\nThere's a `module.js`, for example:\n\n```\nexport const calculate = (a, b) =\u003e a + b;\n```\n\nHow to mock it?\n\n**Mock a module with jest.mock**\n\nCommon approach is to use `jest.mock` to automatically set all exports of a module to the Mock Function.\n\n```\nimport * as module from \"./module\";\n\njest.mock(\"./module.js\");\n\ntest(\"calls module.calculate\", () =\u003e {\n  module.calculate(1, 2);\n  expect(module.calculate).toHaveBeenCalledWith(1, 2);\n});\n\n```\n\n**Mock a function with jest.spyOn + mockImplementation**\n\nYou can mock a function then restore the original implementation:\n\n```\nimport * as module from \"./module\";\n\ntest(\"calls math.calculate\", () =\u003e {\n  const calculateMock = jest.spyOn(module, \"calculate\");\n\n  calculateMock.mockImplementation(() =\u003e 42);\n\n  expect(module.calculate(1, 2)).toEqual(42);\n\n  calculateMock.mockRestore();\n\n  expect(calculateMock).toHaveBeenCalledWith(1, 2);\n});\n```\n\n#### `xcrun: error: SDK \"iphoneos\" cannot be located` issue\n`sudo xcode-select --switch /Applications/Xcode.app`\n\n#### Fonts\nGood tutorial how to add custom fonts: https://medium.com/@mehran.khan/ultimate-guide-to-use-custom-fonts-in-react-native-77fcdf859cf4\n\n## Typescript\n\n#### Use type predicate for functions like `filter` to alter output type\n```TypeScript\nconst sleepMeasurements: (number | undefined)[]\nconst filteredMeasurements = sleepMeasurements.filter((v) =\u003e v !== undefined)) // will be (number | undefined)[]\n// now use type predicate\nconst filteredMeasurements = sleepMeasurements.filter((v): v is number =\u003e v !== undefined)) // will be (number)[]\n```\nYou can read more here [User-Defined Type Guards](https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards)\n\n#### Determine array element's type\n```TypeScript\ntype Some = ['A', 'B', 'C']\ntype AnyOfSome = Some[number] // type AnyOfSome = 'A' | 'B' | 'C'\n```\n\n## Backend Python\n\n#### Always use _id instead of id in search params\nAidbox accepts both id and _id search params. But according to spec https://www.hl7.org/fhir/search.html the only valid param is `_id`. This is causing problems with access policies and may cause potential issues in future.\nSo it'd be better to always use \"_id\" instead of \"id\" search params on frontend as well as backend part of an app.\n\n#### Always user \"token\" type for SearchParameter instead of \"string\"\nMistakenly we use \"string\" as SearchParameter.type for some attributes with type \"text\", but it leads to serious issues, because FHIR search works as full-text search with substring partial matching. Example: SearchParameter User.email must have \"token\" type.\n\nSee [FHIR Search](https://www.hl7.org/fhir/search.html#ptypes) specification about how different SearchParameter types work.\n\n#### Try to avoid subscription in favor of the custom operation\nIf you need to mutate the original resource before/after save - use the custom operation to do it. It has some benefits:\n* Version id won't be increased twice\n* Easier to test\n* You can make transactional queries: all or nothing\n\n#### Don't use the display in references\nUsing `display` in references is a bad idea because it is denormalization and the original title can be changed so that you will need to actualize it. Actualization is a very difficult process and has some drawbacks:\n* It changes version ID --- our UI usually can't handle version mismatch\n* It takes time - you need to go through the database and find all references\n* It can't work with other subscriptions (because actualization is a best practice for subscriptions)\n\nIf you don't want to have a headache with these problems, consider using `_include` every time to get the actual value.\n\n#### User resource role in the system\nUser resources must contain only credentials and links to appropriate Patient/Practitioner. \n\nPractitioners can be used for admin roles and other roles (see FHIR spec for details). \nUsing references to `User` should be forbidden because makes a potential vulnerability (because of _include/_assoc that is not forbidden by default). Instead of this, always make references to appropriate Patient/Practitioner.\n\n#### Access policy rules\nThey always should have `additionalProperties: false` for search params to forbid passing `_assoc/_include/_revinclude`.\n\n\n#### Avoid using access_policy argument in the custom operation\nUsing `access_policy` argument in the customer operation makes it difficult to maintain policies for different roles\n\n\n#### Generate future datetime ranges with DST/STD time shifting\nIn many countries there is a Daylight saving time shifting. While generating future time ranges it is necessary to consider such shiftings.\n\nIn Israel, DST-\u003eSTD in 2020 is occuring on October 25.\nFor example, there is a task to generate a datetime range from October 20 for 7 days with the 1 day step.\n\nThis code will prevent to an error starting from October 25, because `datetime.timedelta` doesn't consider the DST-\u003eSTD time shift:\n\n```\nwhile current_date \u003c end_date:\n  # datetime.timedelta doesn't consider time shifting\n  current_date += datetime.timedelta(days=1)\n```\n\nTo fix this use DST shift adding/subtraction:\n\n```\nnext_date = current_date + datetime.timedelta(days=1)\n\n# Normalize datetime to the local timezone considering DST/STD\nnext_date = next_date.tzinfo.normalize(next_date)\n\n# Add/subtract DST (3600 seconds) /STD (0 seconds) time shift\nnext_date = next_date + (current.dst() - next_date.dst())\n```\n\nDo not forget to cover this logic with tests by checking that all time values (hours, minutes, etc) in your range are equal and the range parts quantity is correct\n\n\n#### Create resources via dict not via args\n**Bad**\n```python\norganization = sdk.client.resource(\n  \"Organization\",\n  name=\"beda.software\",\n  active=False,\n  someAttribute=\"attribute value\"\n)\n```\n\n**Good**\n```python\norganization = sdk.client.resource(\n  \"Organization\",\n  **{\"name\": \"beda.software\", \"active\": False, \"someAttribute\": \"attribute value\"}\n)\n```\n\n\n#### Use dasherize search parameters names and URL paths in operations\n**Bad**\n```python\n\"Encounter.hasInvoice\": {\n  \"name\": \"hasInvoice\",\n  #...\n},\n```\n\n**Good**\n```python\n\"Encounter.has-invoice\": {\n  \"name\": \"has-invoice\",\n  #...\n},\n```\n\n**Bad**\n```python\n@sdk.operation([\"GET\"], [\"Resource\", {\"name\": \"resource_id\"}, \"$operation_with_resource\"])\n```\n\nor\n\n```python\n@sdk.operation([\"GET\"], [\"Resource\", {\"name\": \"resourceId\"}, \"$operationWithResource\"])\n```\n\n**Good**\n```python\n@sdk.operation([\"GET\"], [\"Resource\", {\"name\": \"resource-id\"}, \"$operation-with-resource\"])\n```\n\n### QA, Backend Tests\n\n#### Mocking free functions\nUse module path the function is looked up in (it might be different from the module that defines the function).\n[Official unittest documentation has a detailed description](https://docs.python.org/3/library/unittest.mock.html#where-to-patch)\n\n\n\n## Aidbox\n### Aidbox Migrations\nWe can use Aidbox REST Console to run SQL queries.\n\nReference: [Postgres JSON Functions and Operators](https://www.postgresql.org/docs/current/functions-json.html)\n\n#### Ex. 1: Deletion of an aidbox resource attribute\n\nUpdated resource example (the filter attribute to be deleted):\n```yaml\nid: d6fdcc6a-4513-45df-8f06-797a4727ce7f\nresourceType: MedicalRule\nsourceQuery:\n  id: Source\n  type: batch\n  entry:\n    - request:\n        url: $snowstorm\n        method: POST\n      resource:\n        ecl: '\u003c\u003c 372586001 |Hypotensive agent (substance)|'\n        filter: '...'  // \u003c- to be deleted\n        resourceType: SnowstormRequest\n```\n\nMigration SQL query (for all resources of this type):\n```sql\nupdate medicalrule \nset resource = jsonb_set(\n   resource, \n   '{sourceQuery,entry,0,resource}', \n   (resource #\u003e '{sourceQuery,entry,0,resource}')- 'filter'\n)\n```\n\n### Aidbox Resources\n\n#### How to add an object attribute with Any content to an Aidbox resource\n\n```\n\"Condition.property\": {\n    \"path\": [\"property\"],\n    \"resource\": {\"resourceType\": \"Entity\", \"id\": \"Condition\"},\n    \"extensionUrl\": \"http://beda.software/fhir-extensions/condition-property\",\n    \"schema\": {\"type\": \"object\"},\n},\n```\n\n### Exceptions and OperationOutcome\nIt is better to return Exception or HTTPError in form of [OperationOutcome](http://www.hl7.org/fhir/operationoutcome.html) resource.\n\nYou need [fhirpy](https://pypi.org/project/fhirpy/) or [aidboxpy](https://pypi.org/project/aidboxpy/) version 1.3.0 or higher to import OperationOutcome.\nYou need [aidbox-python-sdk](https://github.com/Aidbox/aidbox-python-sdk/commit/73c71a5b33091865c1bc1af2caa60f6f44539db5) to enable sdk operations return relevant HTTPError if OperationOutcome exception raised.\n\nUsage example:\n```python\nfrom app.sdk import sdk\nfrom fhirpy.base.exceptions import OperationOutcome, IssueType, IssueSeverity\n\n@sdk.operation([\"POST\"], [\"Observation\", \"$create\"], )\nasync def observation_custom_create(operation, request):\n    try:\n        observation_data = request[\"resource\"][\"observation_data\"]\n    except KeyError as e:\n        error_text = f\"Attribute: {str(e)} is required\"\n        raise OperationOutcome(reason=error_text, code=IssueType.required.value, severity=IssueSeverity.error.value)\n\n```\n\n### Backups\n#### Restore backup to local dev environment\n```\ndocker-compose up -d devbox-db\ncat backup.dump |  docker exec -i environment_devbox-db_1 pg_restore  -d devbox\n```\n\n### Emacs\n#### Crash with watching hidden files\nhttps://github.com/facebook/create-react-app/pull/10706/files\n```\ncurl  https://raw.githubusercontent.com/facebook/create-react-app/a3dd649530f4c0c305fc183842399c9d36ecf97f/packages/react-dev-utils/ignoredFiles.js \u003e node_modules/react-dev-utils/ignoredFiles.js\ncurl  https://raw.githubusercontent.com/facebook/create-react-app/a3dd649530f4c0c305fc183842399c9d36ecf97f/packages/react-dev-utils/ignoredFiles.js \u003e ./node_modules/react-scripts/node_modules/react-dev-utils/ignoredFiles.js\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeda-software%2Ffaq","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbeda-software%2Ffaq","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbeda-software%2Ffaq/lists"}