Skip to content

Instantly share code, notes, and snippets.

@izelnakri
Last active February 25, 2021 00:57
Show Gist options
  • Select an option

  • Save izelnakri/1bef99f6af0a3c14ba996280cd53dd22 to your computer and use it in GitHub Desktop.

Select an option

Save izelnakri/1bef99f6af0a3c14ba996280cd53dd22 to your computer and use it in GitHub Desktop.
Ember-data + Memserver + Ecto(ORM) API unification && Memserver + Express.js API unification
import { from, where, join, leftJoin, innerJoin } from 'memserver/query';
import { cast, validat cast, validateRequired, validateFormat, validateLength, uniqueConstraint, foreignKeyConstraint } from 'memserver/changeset';
let userFirstNames = User
|> where('u', 'u.id < 200') // 'm' because there could be multiple model references on |> sql joins()
|> select('u', 'u.first_name')
|> Repo.all
// or maybe some API like this as well: https://apidock.com/rails/ActiveRecord/QueryMethods/where
// or direct memserver like API User.findBy({});
export default class EmailValidator {
static changeset(oldInstance: Email, paramsToCastValidate: object): Changeset {
return oldInstance
|> cast(paramsToCastValidate, ['address'])
|> validateRequired(['address'])
|> validateFormat('address', /@/)
|> validateLength('address', { min: 3, max: 75 })
|> uniqueConstraint('address')
|> foreignKeyConstraint('person_id') // some like this one maybe not needed I can express them as decorators in the model def
}
static userRegistrationChangeset(oldInstance: Email, paramsToCastValidate: object): Changeset {
return oldInstance
|> cast(paramsToCastValidate, ['person_id'])
|> changeset(paramsToCastValidate)
|> validateRequired(['person_id'])
|> this.generateConfirmationToken()
}
// ... with static generateConfirmationToken() {} uses cast(changeset, ['confirmation_token'], generatedToken) inside
}
import express from 'memserver/express';
import User from "./models/user";
const app = express({ mock: !!process.env.MOCK_SERVER });
app.get("/users", ({ params, query, headers }, res) => {
return res.json({ users: User.serializer(User.findAll()) });
});
export default app;
// so exported app can be listened to via another "server-only" file or frontend: app.listen(process.env.HTTP_PORT);
// AREAS TO CONSIDER for rewriting express api:
// ============================================
// 1 - noop-ing express-specific middleware or other code
// 2 - openapi doc generation for express endpoints
// 3 - res.json() vs return $model -> res.json() is necessary for background jobs etc
// 4 - also check nest.js openapi integration
// Then thing re-implementing passthrough(proxy) external link?, namespace, urlPrefix, timing, logging
// OPEAN API GENERATION
// ==========================
// api info name, description
// HTTP TYPE | endpoint string | params, description(md)
// request Types -> response Types header, queryParams, requestBody
// response status codes, response header, response body // description for each type?
// parse the types of queryParam, response keys
// GET /users ? where to description
// all parameter parsing
// response returns
// MODEL API:
import Model,{ belongsTo, hasMany } from 'memserver/model';
class User extends Model {
static Adapter: MemoryAdapter, // or SQLAdapter, JSONAPIAdapter, JSONAdapter, GraphQLAdapter
static Serializer: ModelSerializer // or JSONSerializer, JSONAPISerializer, GraphQLSerializer
static primaryKey = 'id' // or uuid or function(?)
// also attribute declaration here as typescript or from ember-data to TS migration
person = belongsTo();
emails = hasMany();
static insert(options) {
}
static update(options) {
}
static delete(options) {
}
static serializer(userOrUsers) {
}
static serialize(user) {
}
static resetDatabase(targetInitialState: object[]) {
}
// Model Query Interface:
static find(idOrIds) {
}
static findBy(options) {
}
static findAll(options) {
}
static count(options) { // in memory, or in the resource through adapter with options?
}
// Extra examples: customAPIActions:
static confirm = APIAction({
type: 'POST',
path: 'confirmation.microservice.com/user/confirm',
before() {
},
after() {
}
})
// private API: attributes, DB, defaultAttributes(string or lazy(with functions)) in future maybe as prop or decorator etc
// maybe default App or DB validations expressed as decorators
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment