Question:
How to use JSON:API along with Angular/RxJs?

Problem

I have a (Laravel) API that is following >json:api spec. Everything is working great—using Postman I'm able to make requests for related resources and such.


I am using Angular for my front-end, but I'm struggling to understand how to consume this api.


I have been reading through >this SO thread as a starting point.


I am using >ngrx for state management; I'm able to successfully make the appropriate request(s) needed to get data from my api. Where I am struggling is how to handle the response properly.


Here is an example response from my request to get an organization:


// response from /api/v1/organization/:id


data: {...}

jsonapi: {...}

links: {...}


Here is my Organization interface:


export interface IOrganization {

    data: object;

    jsonapi: object;

    links: object;


    // before json:api I would just use the below attributes

    id?: string;

    name: string;

    streetAddress1: string;

    createdAt?: Date;

    updatedAt?: Date;

    deletedAt?: Date;

}


Before using json:api, this class was super straight-forward. But since all of the data is now inside of data.attributes I'm not sure how to correctly structure this interface.


Here is what a good portion of my organization.effects file looks like:



return this._organizationService

    .getOrganization(action.organizationId)

    .pipe(

        tap((organization) => {

            console.log(organization);   // {data:{...}, jsonapi: {...}, data:{...}

        }),

        map((organization) =>

            OrganizationApiActions.loadOrganizationSuccess({

                organization,

            })

   ),

   catchError((error) => {...}

    ...


Is the solution to just drill down through the attributes here?


organization.data.id;

organization.data.attributes.name;

Or is there a more logical way to consume this api? I have seen the ngx-jsonapi package. I don't know if that's overkill here?


In the past using vue.js I have just used the jsona npm package


What is the ideal way to consume a json:api (rest api)?


Solution

If you're not directly consuming the API as is (backend for frontend) then


  • have 2 interface models,

  • one that describes the backend response (ideally codegen or inferred rather than manually written)

  • and the frontend model you want to map to

  • use a function that maps the backend object to frontend

  • use on receiving a response.


const mapJsonApiToOrganization = () =>

  map((response: OrganizationResponse) => {

    const { id, attributes } = response.data;

    return {

      id,

      name: attributes.name,

      streetAddress1: attributes.streetAddress1,

      // ... other mappings

    };

  });


// In your effect

return this._organizationService.getOrganization(action.organizationId).pipe(

  mapJsonApiToOrganization(),

  // from here frontend model only

  map((organization: Organization) => OrganizationApiActions.loadOrganizationSuccess({ organization })),

);


Imo I would keep data passed to ngrx frontend model only. If you change your backend you'd want to only change the mapping function.


Using 3rd party packages is a judgment call. If it's just those 5 properties for the frontend model drilling seems fine.


Suggested blogs:

>What is the Idiomatic way to write a Typescript function with casting

>Why Redux-toolkit payload don't reconigze type in TypeScript?

>TypeScript: Define a type that refers type parameter from another line?

>Solve return type on TypeScript with boolean check doesn't seem to work

>How to fix TS2551: Property toSpliced does not exist on type Array

>Making an argument required if generic interface as no properties

>How to make argument required if generic interface as no properties?

>Cause a type error when a function returns any in TypeScript?

>Library isn’t work in Nestjs useGlobalFilters with library in TypeScript

>How to get the last cell with data for a given column in TypeScript?

>Ignore requests by interceptors based on request content in TypeScript?

>Create data with Typescript Sequelize model without passing in an id?

>How to delete duplicate names from Array in Typescript?


Nisha Patel

Nisha Patel

Submit
0 Answers