@rest-api/react-models
TypeScript icon, indicating that this package has built-in type declarations

2.2.8 • Public • Published

@rest-api/react-models

npm version codecov

Make your React project easier to maintain with this package.

Benefits:

  • You will gain a more typed project (if you are using Typescript)
  • All ajax calls are stored on redux, your endpoint is only called on necessary
  • Better structure on your project

Caution: if you have some random typescript error (pex: ts2589) on creating or editing models, kill the process and restart npm start (on Visual Studio Code restart program).

Features

  • Added nullable argument to schema fields
  • Added initialized variable for all requests (if not initialized, is not requested)

Major changes

From v1

  • Upgraded typescript version and needs your proyect version >=3.9.3 (and react-scripts >= 3.4.1, if you don't eject your project)
  • Required and idOnly don't need to import from library since upgraded typescript version
  • A model on a schema represents the schema of model (for represent the primary key, needs to pass idOnly argument)
  • Connect methods deleted (deprecated on v1)
  • Added more flexibility on models generation adding methods ("getSubModelWithKey" and "getSearchSubModel") to models

From v0

  • On model creation don't need to pass a model name. This major includes a refactor and some bug fixes and features.

File structure

This code examples follows this src structure:

src
└-- models
|   └-- bookModel.ts
|   └-- libraryModel.ts
└-- containers
|   └-- bookContainer.tsx
|   └-- libraryContainer.tsx
└-- views
|   └-- bookView.tsx
|   └-- libraryContainer.tsx
└-- index.tsx

Provider

First of all you need to insert on your index.tsx the provider from application.

...
import { getProvider } from  '@rest-api/react-models';

const ReactModelsProvider = getProvider();


ReactDOM.render(<ReactModelsProvider>
    <App />
</ReactModelsProvider>, document.getElementById('root'));

Declaring models

Declare the models of your application, given a Schema, an id (need to be required field) and a base url:

import { Model, Schema } from  '@rest-api/react-models'

const librarySchema = Schema({
    id: {
        type: Number,
        required: true
    },
    name: String
})
export  default  new  Model(librarySchema, 
    'id', // must be declared as required, string or number and not array or null
    '/api/library')

You can use complex objects on a Schema simplier creating subschemas:

import { Schema } from  '@rest-api/react-models'

const testSchema = Schema({
    subSchema: Schema({
        id: { type: String },
        name: String
    })
})

Represent a field which can be null:

import { Schema } from  '@rest-api/react-models'

const testSchema = Schema({
    nullableField: { 
        type: String, 
        nullable: true, 
        required: true 
    }
})

For a model with metadata, you can represent with following arguments (declaring the data that endpoint sends):

import { Model, Schema } from  '@rest-api/react-models'

const librarySchema = Schema({
    id: {
        type: Number,
        required: true
    },
    name: String
})
export  default  new  Model(librarySchema, 
    'id', 
    '/api/library',
Schema({
    count: {
        type: Number,
	required: true
    },
    items: [{
        type: librarySchema,
	required: true
    }]
},
data => data.items,
({items, ...metadata}) => metadata,
{} //here optional opts (trailingSlash and headers)
)

And foreign keys of your model can be representated:

import { ModelType, ModelPopulatedType, Schema, Model } from  '@rest-api/react-models'
import libraryModel from './libraryModel'

const bookSchema = Schema({
    id: { type: Number, required: true },
    name: { type: String, required: true },
    description: String,
    library: {
        type: libraryModel,
        required: true,
        idOnly: true
    }
})
export type BookType = ModelType<typeof bookSchema>
export type BookPopulatedType = ModelPopulatedType<typeof bookSchema>
export default new Model(bookSchema, 'id', '/api/book')

An option can be passed to model declaration in order to works with django "trailing slash" or pass custom headers:

new Model(bookSchema, 'id', '/api/book', { trailingSlash: true, headers: { Authorization: "Basic xxxx" } })

New methods of model

If you has an endpoint on a different url that represents same object, now you can use your declared model

getSubModelWithKey method

In order to get an object by a key (not an id, but is unique) this is your method Simple usage:

import bookModel from './bookModel'
export default bookModel.getSubModelWithKey('name', '/api/book/name') 

//url is optional, if not provided will be used url from bookModel

Full control on your url:

import bookModel from './bookModel'
import { Schema } from '@rest-api/react-models'
const optSchema = Schema({ 
    project: { 
        type: Number, 
        required: true 
    }
})
export default bookModel.getSubModelWithKey(optSchema, 'name', ({project}) => `/api/book/${project}/name`)

getSearchSubModel method

This method is in order to work as "useGet" or "useGetPopulated", but in other url

Simple usage:

import bookModel from './bookModel'
export default bookModel.getSearchSubModel('api/book/hector') 

Full control on your url:

import bookModel from './bookModel'
import { Schema } from '@rest-api/react-models'
const optSchema = Schema({ 
    author: { 
        type: String,
        required: true 
    }
})
export default bookModel.getSearchSubModel(optSchema, ({author}) => `/api/book/${author}`)

Using on the container

Simple usage

Once you have created a model, you can use it on a container!

Fist clean mode using Typescript, using a hook:

import  React  from  'react'

import  bookModel  from  '../models/bookModel'
import  BookView  from  '../views/bookView'


export default () => {
	const { items, loading, error, initialized } = bookModel.useGet()
    if (!initialized) <p>Request not fetched</p>
	if (error) return  <p>There are an error with the request</p>
	if (loading) return  <p>Loading...</p>
	return  <ul>{
		items.map(i  =>  <BookView  name={i.name}  />)
	}</ul>
}

Populate items

This feature populate foreign key if these ones aren't fetched. It's recommended to fetch beore this call the objects using useGet (pex: on Apps initialization). The ajax method will be called only on necessary (if there are some object not fetched).

You can populate items with a simple usage (you need to check if it's populated, if you want to use a placeholder):

import React from 'react'

import bookModel from '../models/bookModel'

export default () => {
    const { loading, error, ...result } = bookModel.useGetPopulated()

    if (error) return <p>There are an error with the request</p>
    if (loading) return <p>Loading...</p>
    return <table>
	<thead>
	    <tr>
		<th>Id</th>
		<th>Name</th>
		<th>Library name</th>
	    </tr>
	</thead>
	<tbody>
	    {
		result.populated ?
		result.items.map(i => <React.Fragment key={i.id}>
		    <td>{i.id}</td>
		    <td>{i.name}</td>
		    <td>{i.library.name}</td>
		</React.Fragment>) :
		result.items.map(i => <React.Fragment key={i.id}>
		    <td>{i.id}</td>
		    <td>{i.name}</td>
		    <td>{i.library.name ?? 'Loading ...'}</td>
		</React.Fragment>)
	    }
	</tbody>
    </table>
}

Use methods (POST, PUT, PATCH, DELETE)

In order to access to one of those methods, select the correct hook (usePost, usePut, usePatch or useDelete)

import React from 'react'

import { ModelType, HttpError } from '@rest-api/react-models'
import bookModel from '../models/bookModel'
import { useHistory } from 'react-router-dom'

export default () => {
    const post = bookModel.usePost()
    const [data, setData] = React.useState<ModelType<typeof bookModel>|null>(null)
    const history = useHistory()
    const [error, setError] = React.useState<HttpError|null>(null)
    
    function handleSubmit(ev){
        ev.preventDefault()
        if(data)
            post(data, (err, res) => {
                if(err) //there are an error with request
                    return setError(err)
                history.push('to the new path')
            })
    }

    return ...
}

Package Sidebar

Install

npm i @rest-api/react-models

Weekly Downloads

4

Version

2.2.8

License

MIT

Unpacked Size

282 kB

Total Files

93

Last publish

Collaborators

  • hector7